xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/Hash.cpp (revision 5b27928474e6a4103d65b347544705c40c9618fd)
10b57cec5SDimitry Andric //===- Hash.cpp - PDB Hash Functions --------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/Hash.h"
100b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
11*8bcb0991SDimitry Andric #include "llvm/Support/CRC.h"
120b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
130b57cec5SDimitry Andric #include <cstdint>
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric using namespace llvm;
160b57cec5SDimitry Andric using namespace llvm::support;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric // Corresponds to `Hasher::lhashPbCb` in PDB/include/misc.h.
190b57cec5SDimitry Andric // Used for name hash table and TPI/IPI hashes.
hashStringV1(StringRef Str)200b57cec5SDimitry Andric uint32_t pdb::hashStringV1(StringRef Str) {
210b57cec5SDimitry Andric   uint32_t Result = 0;
220b57cec5SDimitry Andric   uint32_t Size = Str.size();
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric   ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()),
250b57cec5SDimitry Andric                               Size / 4);
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric   for (auto Value : Longs)
280b57cec5SDimitry Andric     Result ^= Value;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric   const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end());
310b57cec5SDimitry Andric   uint32_t RemainderSize = Size % 4;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   // Maximum of 3 bytes left.  Hash a 2 byte word if possible, then hash the
340b57cec5SDimitry Andric   // possibly remaining 1 byte.
350b57cec5SDimitry Andric   if (RemainderSize >= 2) {
360b57cec5SDimitry Andric     uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder);
370b57cec5SDimitry Andric     Result ^= static_cast<uint32_t>(Value);
380b57cec5SDimitry Andric     Remainder += 2;
390b57cec5SDimitry Andric     RemainderSize -= 2;
400b57cec5SDimitry Andric   }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   // hash possible odd byte
430b57cec5SDimitry Andric   if (RemainderSize == 1) {
440b57cec5SDimitry Andric     Result ^= *(Remainder++);
450b57cec5SDimitry Andric   }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   const uint32_t toLowerMask = 0x20202020;
480b57cec5SDimitry Andric   Result |= toLowerMask;
490b57cec5SDimitry Andric   Result ^= (Result >> 11);
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   return Result ^ (Result >> 16);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric // Corresponds to `HasherV2::HashULONG` in PDB/include/misc.h.
550b57cec5SDimitry Andric // Used for name hash table.
hashStringV2(StringRef Str)560b57cec5SDimitry Andric uint32_t pdb::hashStringV2(StringRef Str) {
570b57cec5SDimitry Andric   uint32_t Hash = 0xb170a1bf;
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   ArrayRef<char> Buffer(Str.begin(), Str.end());
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   ArrayRef<ulittle32_t> Items(
620b57cec5SDimitry Andric       reinterpret_cast<const ulittle32_t *>(Buffer.data()),
630b57cec5SDimitry Andric       Buffer.size() / sizeof(ulittle32_t));
640b57cec5SDimitry Andric   for (ulittle32_t Item : Items) {
650b57cec5SDimitry Andric     Hash += Item;
660b57cec5SDimitry Andric     Hash += (Hash << 10);
670b57cec5SDimitry Andric     Hash ^= (Hash >> 6);
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric   Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t));
700b57cec5SDimitry Andric   for (uint8_t Item : Buffer) {
710b57cec5SDimitry Andric     Hash += Item;
720b57cec5SDimitry Andric     Hash += (Hash << 10);
730b57cec5SDimitry Andric     Hash ^= (Hash >> 6);
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   return Hash * 1664525U + 1013904223U;
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric // Corresponds to `SigForPbCb` in langapi/shared/crc32.h.
hashBufferV8(ArrayRef<uint8_t> Buf)800b57cec5SDimitry Andric uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) {
810b57cec5SDimitry Andric   JamCRC JC(/*Init=*/0U);
82*8bcb0991SDimitry Andric   JC.update(Buf);
830b57cec5SDimitry Andric   return JC.getCRC();
840b57cec5SDimitry Andric }
85