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 Andricuint32_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 Andricuint32_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 Andricuint32_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