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 Andric uint32_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 Andric uint32_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 Andric uint32_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