[llvm] r319854 - [CodeView] Add support for content hashing CodeView type records.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 5 15:08:59 PST 2017


Author: zturner
Date: Tue Dec  5 15:08:58 2017
New Revision: 319854

URL: http://llvm.org/viewvc/llvm-project?rev=319854&view=rev
Log:
[CodeView] Add support for content hashing CodeView type records.

Currently nothing uses this, but this at least gets the core
algorithm in, and adds some test to demonstrate correctness.

Differential Revision: https://reviews.llvm.org/D40736

Added:
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeHashing.h
    llvm/trunk/lib/DebugInfo/CodeView/TypeHashing.cpp
    llvm/trunk/unittests/DebugInfo/CodeView/TypeHashingTest.cpp
Modified:
    llvm/trunk/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
    llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt
    llvm/trunk/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp
    llvm/trunk/unittests/DebugInfo/CodeView/CMakeLists.txt

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h?rev=319854&r1=319853&r2=319854&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h Tue Dec  5 15:08:58 2017
@@ -16,6 +16,7 @@
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h"
 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/Support/Allocator.h"
 #include <cassert>
@@ -27,13 +28,6 @@ namespace llvm {
 namespace codeview {
 
 class ContinuationRecordBuilder;
-class TypeHasher;
-
-struct HashedType {
-  hash_code Hash;
-  ArrayRef<uint8_t> Data;
-  TypeIndex Index;
-};
 
 class MergingTypeTableBuilder : public TypeCollection {
   /// Storage for records.  These need to outlive the TypeTableBuilder.
@@ -45,14 +39,11 @@ class MergingTypeTableBuilder : public T
   SimpleTypeSerializer SimpleSerializer;
 
   /// Hash table.
-  DenseSet<HashedType> HashedRecords;
+  DenseMap<LocallyHashedType, TypeIndex> HashedRecords;
 
   /// Contains a list of all records indexed by TypeIndex.toArrayIndex().
   SmallVector<ArrayRef<uint8_t>, 2> SeenRecords;
 
-  /// Contains a list of all hash codes index by TypeIndex.toArrayIndex().
-  SmallVector<hash_code, 2> SeenHashes;
-
 public:
   explicit MergingTypeTableBuilder(BumpPtrAllocator &Storage);
   ~MergingTypeTableBuilder();
@@ -73,7 +64,6 @@ public:
   BumpPtrAllocator &getAllocator() { return RecordStorage; }
 
   ArrayRef<ArrayRef<uint8_t>> records() const;
-  ArrayRef<hash_code> hashes() const;
 
   TypeIndex insertRecordAs(hash_code Hash, ArrayRef<uint8_t> &Record);
   TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record);

Added: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeHashing.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeHashing.h?rev=319854&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeHashing.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeHashing.h Tue Dec  5 15:08:58 2017
@@ -0,0 +1,119 @@
+//===- TypeHashing.h ---------------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEHASHING_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPEHASHING_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+
+namespace llvm {
+namespace codeview {
+
+/// A locally hashed type represents a straightforward hash code of a serialized
+/// record.  The record is simply serialized, and then the bytes are hashed by
+/// a standard algorithm.  This is sufficient for the case of de-duplicating
+/// records within a single sequence of types, because if two records both have
+/// a back-reference to the same type in the same stream, they will both have
+/// the same numeric value for the TypeIndex of the back reference.
+struct LocallyHashedType {
+  hash_code Hash;
+  ArrayRef<uint8_t> RecordData;
+
+  static LocallyHashedType hashType(ArrayRef<uint8_t> RecordData);
+};
+
+/// A globally hashed type represents a hash value that is sufficient to
+/// uniquely identify a record across multiple type streams or type sequences.
+/// This works by, for any given record A which references B, replacing the
+/// TypeIndex that refers to B with a previously-computed global hash for B.  As
+/// this is a recursive algorithm (e.g. the global hash of B also depends on the
+/// global hashes of the types that B refers to), a global hash can uniquely
+/// identify identify that A occurs in another stream that has a completely
+/// different graph structure.  Although the hash itself is slower to compute,
+/// probing is much faster with a globally hashed type, because the hash itself
+/// is considered "as good as" the original type.  Since type records can be
+/// quite large, this makes the equality comparison of the hash much faster than
+/// equality comparison of a full record.
+struct GloballyHashedType {
+  GloballyHashedType() = default;
+  GloballyHashedType(StringRef H)
+      : GloballyHashedType(ArrayRef<uint8_t>(H.bytes_begin(), H.bytes_end())) {}
+  GloballyHashedType(ArrayRef<uint8_t> H) {
+    assert(H.size() == 20);
+    ::memcpy(Hash.data(), H.data(), 20);
+  }
+  std::array<uint8_t, 20> Hash;
+
+  /// Given a sequence of bytes representing a record, compute a global hash for
+  /// this record.  Due to the nature of global hashes incorporating the hashes
+  /// of referenced records, this function requires a list of types and ids
+  /// that RecordData might reference, indexable by TypeIndex.
+  static GloballyHashedType hashType(ArrayRef<uint8_t> RecordData,
+                                     ArrayRef<GloballyHashedType> PreviousTypes,
+                                     ArrayRef<GloballyHashedType> PreviousIds);
+
+  /// Given a sequence of combined type and ID records, compute global hashes
+  /// for each of them, returning the results in a vector of hashed types.
+  template <typename Range>
+  static std::vector<GloballyHashedType> hashTypes(Range &&Records) {
+    std::vector<GloballyHashedType> Hashes;
+    Hashes.reserve(std::distance(std::begin(Records), std::end(Records)));
+    for (const auto &R : Records)
+      Hashes.push_back(hashType(R, Hashes, Hashes));
+
+    return Hashes;
+  }
+};
+} // namespace codeview
+
+template <> struct DenseMapInfo<codeview::LocallyHashedType> {
+  static codeview::LocallyHashedType Empty;
+  static codeview::LocallyHashedType Tombstone;
+
+  static codeview::LocallyHashedType getEmptyKey() { return Empty; }
+
+  static codeview::LocallyHashedType getTombstoneKey() { return Tombstone; }
+
+  static unsigned getHashValue(codeview::LocallyHashedType Val) {
+    return Val.Hash;
+  }
+
+  static bool isEqual(codeview::LocallyHashedType LHS,
+                      codeview::LocallyHashedType RHS) {
+    if (LHS.Hash != RHS.Hash)
+      return false;
+    return LHS.RecordData == RHS.RecordData;
+  }
+};
+
+template <> struct DenseMapInfo<codeview::GloballyHashedType> {
+  static codeview::GloballyHashedType Empty;
+  static codeview::GloballyHashedType Tombstone;
+
+  static codeview::GloballyHashedType getEmptyKey() { return Empty; }
+
+  static codeview::GloballyHashedType getTombstoneKey() { return Tombstone; }
+
+  static unsigned getHashValue(codeview::GloballyHashedType Val) {
+    return *reinterpret_cast<const unsigned *>(Val.Hash.data());
+  }
+
+  static bool isEqual(codeview::GloballyHashedType LHS,
+                      codeview::GloballyHashedType RHS) {
+    return LHS.Hash == RHS.Hash;
+  }
+};
+
+} // namespace llvm
+
+#endif

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h?rev=319854&r1=319853&r2=319854&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h Tue Dec  5 15:08:58 2017
@@ -334,6 +334,11 @@ public:
   uint32_t Attrs;
   Optional<MemberPointerInfo> MemberInfo;
 
+  void setAttrs(PointerKind PK, PointerMode PM, PointerOptions PO,
+                uint8_t Size) {
+    Attrs = calcAttrs(PK, PM, PO, Size);
+  }
+
 private:
   static uint32_t calcAttrs(PointerKind PK, PointerMode PM, PointerOptions PO,
                             uint8_t Size) {

Modified: llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt?rev=319854&r1=319853&r2=319854&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt Tue Dec  5 15:08:58 2017
@@ -32,6 +32,7 @@ add_llvm_library(LLVMDebugInfoCodeView
   TypeDumpVisitor.cpp
   TypeIndex.cpp
   TypeIndexDiscovery.cpp
+  TypeHashing.cpp
   TypeRecordMapping.cpp
   TypeStreamMerger.cpp
   TypeTableCollection.cpp

Modified: llvm/trunk/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp?rev=319854&r1=319853&r2=319854&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp Tue Dec  5 15:08:58 2017
@@ -28,27 +28,6 @@
 using namespace llvm;
 using namespace llvm::codeview;
 
-static HashedType Empty{0, {}, TypeIndex::None()};
-static HashedType Tombstone{hash_code(-1), {}, TypeIndex::None()};
-
-namespace llvm {
-
-template <> struct DenseMapInfo<HashedType> {
-  static inline HashedType getEmptyKey() { return Empty; }
-
-  static inline HashedType getTombstoneKey() { return Tombstone; }
-
-  static unsigned getHashValue(HashedType Val) { return Val.Hash; }
-
-  static bool isEqual(HashedType LHS, HashedType RHS) {
-    if (RHS.Hash != LHS.Hash)
-      return false;
-    return RHS.Data == LHS.Data;
-  }
-};
-
-} // end namespace llvm
-
 TypeIndex MergingTypeTableBuilder::nextTypeIndex() const {
   return TypeIndex::fromArrayIndex(SeenRecords.size());
 }
@@ -56,7 +35,6 @@ TypeIndex MergingTypeTableBuilder::nextT
 MergingTypeTableBuilder::MergingTypeTableBuilder(BumpPtrAllocator &Storage)
     : RecordStorage(Storage) {
   SeenRecords.reserve(4096);
-  SeenHashes.reserve(4096);
 }
 
 MergingTypeTableBuilder::~MergingTypeTableBuilder() = default;
@@ -102,13 +80,8 @@ ArrayRef<ArrayRef<uint8_t>> MergingTypeT
   return SeenRecords;
 }
 
-ArrayRef<hash_code> MergingTypeTableBuilder::hashes() const {
-  return SeenHashes;
-}
-
 void MergingTypeTableBuilder::reset() {
   HashedRecords.clear();
-  SeenHashes.clear();
   SeenRecords.clear();
 }
 
@@ -124,18 +97,19 @@ TypeIndex MergingTypeTableBuilder::inser
   assert(Record.size() < UINT32_MAX && "Record too big");
   assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
 
-  HashedType TempHashedType = {Hash, Record, nextTypeIndex()};
-  auto Result = HashedRecords.insert(TempHashedType);
+  LocallyHashedType WeakHash{Hash, Record};
+  auto Result = HashedRecords.try_emplace(WeakHash, nextTypeIndex());
 
   if (Result.second) {
-    Result.first->Data = stabilize(RecordStorage, Record);
-    SeenRecords.push_back(Result.first->Data);
-    SeenHashes.push_back(Result.first->Hash);
+    ArrayRef<uint8_t> RecordData = stabilize(RecordStorage, Record);
+    Result.first->first.RecordData = RecordData;
+    SeenRecords.push_back(RecordData);
   }
 
   // Update the caller's copy of Record to point a stable copy.
-  Record = Result.first->Data;
-  return Result.first->Index;
+  TypeIndex ActualTI = Result.first->second;
+  Record = SeenRecords[ActualTI.toArrayIndex()];
+  return ActualTI;
 }
 
 TypeIndex

Added: llvm/trunk/lib/DebugInfo/CodeView/TypeHashing.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeHashing.cpp?rev=319854&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeHashing.cpp (added)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeHashing.cpp Tue Dec  5 15:08:58 2017
@@ -0,0 +1,74 @@
+//===- TypeHashing.cpp -------------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
+
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/Support/SHA1.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+LocallyHashedType DenseMapInfo<LocallyHashedType>::Empty{0, {}};
+LocallyHashedType DenseMapInfo<LocallyHashedType>::Tombstone{hash_code(-1), {}};
+
+static std::array<uint8_t, 20> EmptyHash;
+static std::array<uint8_t, 20> TombstoneHash = {
+    0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+GloballyHashedType DenseMapInfo<GloballyHashedType>::Empty{EmptyHash};
+GloballyHashedType DenseMapInfo<GloballyHashedType>::Tombstone{TombstoneHash};
+
+LocallyHashedType LocallyHashedType::hashType(ArrayRef<uint8_t> RecordData) {
+  return {llvm::hash_value(RecordData), RecordData};
+}
+
+GloballyHashedType
+GloballyHashedType::hashType(ArrayRef<uint8_t> RecordData,
+                             ArrayRef<GloballyHashedType> PreviousTypes,
+                             ArrayRef<GloballyHashedType> PreviousIds) {
+  SmallVector<TiReference, 4> Refs;
+  discoverTypeIndices(RecordData, Refs);
+  SHA1 S;
+  S.init();
+  uint32_t Off = 0;
+  RecordData = RecordData.drop_front(sizeof(RecordPrefix));
+  for (const auto &Ref : Refs) {
+    // Hash any data that comes before this TiRef.
+    uint32_t PreLen = Ref.Offset - Off;
+    ArrayRef<uint8_t> PreData = RecordData.slice(Off, PreLen);
+    S.update(PreData);
+    auto Prev = (Ref.Kind == TiRefKind::IndexRef) ? PreviousIds : PreviousTypes;
+
+    auto RefData = RecordData.slice(Ref.Offset, Ref.Count * sizeof(TypeIndex));
+    // For each type index referenced, add in the previously computed hash
+    // value of that type.
+    ArrayRef<TypeIndex> Indices(
+        reinterpret_cast<const TypeIndex *>(RefData.data()), Ref.Count);
+    for (TypeIndex TI : Indices) {
+      ArrayRef<uint8_t> BytesToHash;
+      if (TI.isSimple() || TI.isNoneType()) {
+        const uint8_t *IndexBytes = reinterpret_cast<const uint8_t *>(&TI);
+        BytesToHash = makeArrayRef(IndexBytes, sizeof(TypeIndex));
+      } else {
+        BytesToHash = Prev[TI.toArrayIndex()].Hash;
+      }
+      S.update(BytesToHash);
+    }
+
+    Off = Ref.Offset + Ref.Count * sizeof(TypeIndex);
+  }
+
+  // Don't forget to add in any trailing bytes.
+  auto TrailingBytes = RecordData.drop_front(Off);
+  S.update(TrailingBytes);
+
+  return {S.final()};
+}

Modified: llvm/trunk/unittests/DebugInfo/CodeView/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/CodeView/CMakeLists.txt?rev=319854&r1=319853&r2=319854&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/CodeView/CMakeLists.txt (original)
+++ llvm/trunk/unittests/DebugInfo/CodeView/CMakeLists.txt Tue Dec  5 15:08:58 2017
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
 
 set(DebugInfoCodeViewSources
   RandomAccessVisitorTest.cpp
+  TypeHashingTest.cpp
   TypeIndexDiscoveryTest.cpp
   )
 

Added: llvm/trunk/unittests/DebugInfo/CodeView/TypeHashingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/CodeView/TypeHashingTest.cpp?rev=319854&view=auto
==============================================================================
--- llvm/trunk/unittests/DebugInfo/CodeView/TypeHashingTest.cpp (added)
+++ llvm/trunk/unittests/DebugInfo/CodeView/TypeHashingTest.cpp Tue Dec  5 15:08:58 2017
@@ -0,0 +1,156 @@
+//===- llvm/unittest/DebugInfo/CodeView/TypeHashingTest.cpp ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
+#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static TypeIndex createPointerRecord(AppendingTypeTableBuilder &Builder,
+                                     TypeIndex TI) {
+  PointerRecord PR(TypeRecordKind::Pointer);
+  PR.setAttrs(PointerKind::Near32, PointerMode::Pointer, PointerOptions::None,
+              4);
+  PR.ReferentType = TI;
+  return Builder.writeLeafType(PR);
+}
+
+static TypeIndex createArgListRecord(AppendingTypeTableBuilder &Builder,
+                                     TypeIndex Q, TypeIndex R) {
+  ArgListRecord AR(TypeRecordKind::ArgList);
+  AR.ArgIndices.push_back(Q);
+  AR.ArgIndices.push_back(R);
+  return Builder.writeLeafType(AR);
+}
+
+static TypeIndex createProcedureRecord(AppendingTypeTableBuilder &Builder,
+                                       uint32_t ParamCount, TypeIndex Return,
+                                       TypeIndex ArgList) {
+  ProcedureRecord PR(TypeRecordKind::Procedure);
+  PR.ArgumentList = ArgList;
+  PR.CallConv = CallingConvention::NearC;
+  PR.Options = FunctionOptions::None;
+  PR.ParameterCount = ParamCount;
+  PR.ReturnType = Return;
+  return Builder.writeLeafType(PR);
+}
+
+static ArrayRef<uint8_t> hash_of(ArrayRef<GloballyHashedType> Hashes,
+                                 TypeIndex TI) {
+  return Hashes[TI.toArrayIndex()].Hash;
+}
+
+static void verifyHashUniqueness(ArrayRef<GloballyHashedType> Hashes) {
+  assert(!Hashes.empty());
+
+  for (size_t I = 0; I < Hashes.size() - 1; ++I) {
+    for (size_t J = I + 1; J < Hashes.size(); ++J) {
+      EXPECT_NE(Hashes[I].Hash, Hashes[J].Hash);
+    }
+  }
+}
+
+TEST(TypeHashingTest, ContentHash) {
+  SimpleTypeSerializer Serializer;
+
+  TypeIndex CharStar(SimpleTypeKind::SignedCharacter,
+                     SimpleTypeMode::NearPointer32);
+
+  BumpPtrAllocator Alloc;
+  AppendingTypeTableBuilder Ordering1(Alloc);
+  AppendingTypeTableBuilder Ordering2(Alloc);
+
+  TypeIndex CharP(SimpleTypeKind::SignedCharacter, SimpleTypeMode::NearPointer);
+  TypeIndex IntP(SimpleTypeKind::Int32, SimpleTypeMode::NearPointer);
+  TypeIndex DoubleP(SimpleTypeKind::Float64, SimpleTypeMode::NearPointer);
+
+  // We're going to the same type sequence with two different orderings, and
+  // then confirm all records are hashed the same.
+
+  TypeIndex CharPP[2];
+  TypeIndex IntPP[2];
+  TypeIndex IntPPP[2];
+  TypeIndex DoublePP[2];
+  TypeIndex Args[2];
+  TypeIndex Proc[2];
+
+  // Ordering 1
+  // ----------------------------------------
+  // LF_POINTER             0x1000   {char**}
+  //   Referent = char*
+  // LF_POINTER             0x1001   {int**}
+  //   Referent = int*
+  // LF_POINTER             0x1002   {int***}
+  //   Referent = 0x1001
+  // LF_ARGLIST             0x1003   {(char**, int***)}
+  //   Arg[0] = 0x1000
+  //   Arg[1] = 0x1002
+  // LF_PROCEDURE           0x1004   {int** func(char**, int***)}
+  //   ArgList = 0x1003
+  //   ReturnType = 0x1001
+  std::vector<GloballyHashedType> Ordering1Hashes;
+  CharPP[0] = createPointerRecord(Ordering1, CharP);
+  IntPP[0] = createPointerRecord(Ordering1, IntP);
+  IntPPP[0] = createPointerRecord(Ordering1, IntPP[0]);
+  Args[0] = createArgListRecord(Ordering1, CharPP[0], IntPPP[0]);
+  Proc[0] = createProcedureRecord(Ordering1, 2, IntPP[0], Args[0]);
+
+  ASSERT_EQ(0x1000U, CharPP[0].getIndex());
+  ASSERT_EQ(0x1001U, IntPP[0].getIndex());
+  ASSERT_EQ(0x1002U, IntPPP[0].getIndex());
+  ASSERT_EQ(0x1003U, Args[0].getIndex());
+  ASSERT_EQ(0x1004U, Proc[0].getIndex());
+
+  auto Hashes1 = GloballyHashedType::hashTypes(Ordering1.records());
+
+  // Ordering 2
+  // ----------------------------------------
+  // LF_POINTER             0x1000   {int**}
+  //   Referent = int*
+  // LF_POINTER             0x1001   {int***}
+  //   Referent = 0x1000
+  // LF_POINTER             0x1002   {char**}
+  //   Referent = char*
+  // LF_POINTER             0x1003   {double**}
+  //   Referent = double*
+  // LF_ARGLIST             0x1004   {(char**, int***)}
+  //   Arg[0] = 0x1002
+  //   Arg[1] = 0x1001
+  // LF_PROCEDURE           0x1005   {int** func(char**, int***)}
+  //   ArgList = 0x1004
+  //   ReturnType = 0x1000
+  IntPP[1] = createPointerRecord(Ordering2, IntP);
+  IntPPP[1] = createPointerRecord(Ordering2, IntPP[1]);
+  CharPP[1] = createPointerRecord(Ordering2, CharP);
+  DoublePP[1] = createPointerRecord(Ordering2, DoubleP);
+  Args[1] = createArgListRecord(Ordering2, CharPP[1], IntPPP[1]);
+  Proc[1] = createProcedureRecord(Ordering2, 2, IntPP[1], Args[1]);
+  auto Hashes2 = GloballyHashedType::hashTypes(Ordering2.records());
+
+  ASSERT_EQ(0x1000U, IntPP[1].getIndex());
+  ASSERT_EQ(0x1001U, IntPPP[1].getIndex());
+  ASSERT_EQ(0x1002U, CharPP[1].getIndex());
+  ASSERT_EQ(0x1003U, DoublePP[1].getIndex());
+  ASSERT_EQ(0x1004U, Args[1].getIndex());
+  ASSERT_EQ(0x1005U, Proc[1].getIndex());
+
+  // Sanity check to make sure all same-ordering hashes are different
+  // from each other.
+  verifyHashUniqueness(Hashes1);
+  verifyHashUniqueness(Hashes2);
+
+  EXPECT_EQ(hash_of(Hashes1, IntPP[0]), hash_of(Hashes2, IntPP[1]));
+  EXPECT_EQ(hash_of(Hashes1, IntPPP[0]), hash_of(Hashes2, IntPPP[1]));
+  EXPECT_EQ(hash_of(Hashes1, CharPP[0]), hash_of(Hashes2, CharPP[1]));
+  EXPECT_EQ(hash_of(Hashes1, Args[0]), hash_of(Hashes2, Args[1]));
+  EXPECT_EQ(hash_of(Hashes1, Proc[0]), hash_of(Hashes2, Proc[1]));
+}




More information about the llvm-commits mailing list