17a7e6055SDimitry Andric //===- Hash.cpp - PDB Hash Functions --------------------------------------===// 27a7e6055SDimitry Andric // 37a7e6055SDimitry Andric // The LLVM Compiler Infrastructure 47a7e6055SDimitry Andric // 57a7e6055SDimitry Andric // This file is distributed under the University of Illinois Open Source 67a7e6055SDimitry Andric // License. See LICENSE.TXT for details. 77a7e6055SDimitry Andric // 87a7e6055SDimitry Andric //===----------------------------------------------------------------------===// 97a7e6055SDimitry Andric 107a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/Hash.h" 117a7e6055SDimitry Andric #include "llvm/ADT/ArrayRef.h" 127a7e6055SDimitry Andric #include "llvm/Support/Endian.h" 137a7e6055SDimitry Andric #include "llvm/Support/JamCRC.h" 14*a580b014SDimitry Andric #include <cstdint> 157a7e6055SDimitry Andric 167a7e6055SDimitry Andric using namespace llvm; 177a7e6055SDimitry Andric using namespace llvm::support; 187a7e6055SDimitry Andric 197a7e6055SDimitry Andric // Corresponds to `Hasher::lhashPbCb` in PDB/include/misc.h. 207a7e6055SDimitry Andric // Used for name hash table and TPI/IPI hashes. hashStringV1(StringRef Str)217a7e6055SDimitry Andricuint32_t pdb::hashStringV1(StringRef Str) { 227a7e6055SDimitry Andric uint32_t Result = 0; 237a7e6055SDimitry Andric uint32_t Size = Str.size(); 247a7e6055SDimitry Andric 257a7e6055SDimitry Andric ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()), 267a7e6055SDimitry Andric Size / 4); 277a7e6055SDimitry Andric 287a7e6055SDimitry Andric for (auto Value : Longs) 297a7e6055SDimitry Andric Result ^= Value; 307a7e6055SDimitry Andric 317a7e6055SDimitry Andric const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end()); 327a7e6055SDimitry Andric uint32_t RemainderSize = Size % 4; 337a7e6055SDimitry Andric 347a7e6055SDimitry Andric // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the 357a7e6055SDimitry Andric // possibly remaining 1 byte. 367a7e6055SDimitry Andric if (RemainderSize >= 2) { 377a7e6055SDimitry Andric uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder); 387a7e6055SDimitry Andric Result ^= static_cast<uint32_t>(Value); 397a7e6055SDimitry Andric Remainder += 2; 407a7e6055SDimitry Andric RemainderSize -= 2; 417a7e6055SDimitry Andric } 427a7e6055SDimitry Andric 437a7e6055SDimitry Andric // hash possible odd byte 447a7e6055SDimitry Andric if (RemainderSize == 1) { 457a7e6055SDimitry Andric Result ^= *(Remainder++); 467a7e6055SDimitry Andric } 477a7e6055SDimitry Andric 487a7e6055SDimitry Andric const uint32_t toLowerMask = 0x20202020; 497a7e6055SDimitry Andric Result |= toLowerMask; 507a7e6055SDimitry Andric Result ^= (Result >> 11); 517a7e6055SDimitry Andric 527a7e6055SDimitry Andric return Result ^ (Result >> 16); 537a7e6055SDimitry Andric } 547a7e6055SDimitry Andric 557a7e6055SDimitry Andric // Corresponds to `HasherV2::HashULONG` in PDB/include/misc.h. 567a7e6055SDimitry Andric // Used for name hash table. hashStringV2(StringRef Str)577a7e6055SDimitry Andricuint32_t pdb::hashStringV2(StringRef Str) { 587a7e6055SDimitry Andric uint32_t Hash = 0xb170a1bf; 597a7e6055SDimitry Andric 607a7e6055SDimitry Andric ArrayRef<char> Buffer(Str.begin(), Str.end()); 617a7e6055SDimitry Andric 627a7e6055SDimitry Andric ArrayRef<ulittle32_t> Items( 637a7e6055SDimitry Andric reinterpret_cast<const ulittle32_t *>(Buffer.data()), 647a7e6055SDimitry Andric Buffer.size() / sizeof(ulittle32_t)); 657a7e6055SDimitry Andric for (ulittle32_t Item : Items) { 667a7e6055SDimitry Andric Hash += Item; 677a7e6055SDimitry Andric Hash += (Hash << 10); 687a7e6055SDimitry Andric Hash ^= (Hash >> 6); 697a7e6055SDimitry Andric } 707a7e6055SDimitry Andric Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t)); 717a7e6055SDimitry Andric for (uint8_t Item : Buffer) { 727a7e6055SDimitry Andric Hash += Item; 737a7e6055SDimitry Andric Hash += (Hash << 10); 747a7e6055SDimitry Andric Hash ^= (Hash >> 6); 757a7e6055SDimitry Andric } 767a7e6055SDimitry Andric 777a7e6055SDimitry Andric return Hash * 1664525U + 1013904223U; 787a7e6055SDimitry Andric } 797a7e6055SDimitry Andric 807a7e6055SDimitry Andric // Corresponds to `SigForPbCb` in langapi/shared/crc32.h. hashBufferV8(ArrayRef<uint8_t> Buf)817a7e6055SDimitry Andricuint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) { 827a7e6055SDimitry Andric JamCRC JC(/*Init=*/0U); 837a7e6055SDimitry Andric JC.update(makeArrayRef<char>(reinterpret_cast<const char *>(Buf.data()), 847a7e6055SDimitry Andric Buf.size())); 857a7e6055SDimitry Andric return JC.getCRC(); 867a7e6055SDimitry Andric } 87