| //===- llvm/CodeGen/StableHashing.h - Utilities for stable hashing * C++ *-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file provides types and functions for computing and combining stable |
| // hashes. Stable hashes can be useful for hashing across different modules, |
| // processes, or compiler runs. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CODEGEN_STABLEHASHING_H |
| #define LLVM_CODEGEN_STABLEHASHING_H |
| |
| #include "llvm/ADT/StringRef.h" |
| |
| namespace llvm { |
| |
| /// An opaque object representing a stable hash code. It can be serialized, |
| /// deserialized, and is stable across processes and executions. |
| using stable_hash = uint64_t; |
| |
| // Implementation details |
| namespace hashing { |
| namespace detail { |
| |
| // Stable hashes are based on the 64-bit FNV-1 hash: |
| // https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function |
| |
| const uint64_t FNV_PRIME_64 = 1099511628211u; |
| const uint64_t FNV_OFFSET_64 = 14695981039346656037u; |
| |
| inline void stable_hash_append(stable_hash &Hash, const char Value) { |
| Hash = Hash ^ (Value & 0xFF); |
| Hash = Hash * FNV_PRIME_64; |
| } |
| |
| inline void stable_hash_append(stable_hash &Hash, stable_hash Value) { |
| for (unsigned I = 0; I < 8; ++I) { |
| stable_hash_append(Hash, static_cast<char>(Value)); |
| Value >>= 8; |
| } |
| } |
| |
| } // namespace detail |
| } // namespace hashing |
| |
| inline stable_hash stable_hash_combine(stable_hash A, stable_hash B) { |
| stable_hash Hash = hashing::detail::FNV_OFFSET_64; |
| hashing::detail::stable_hash_append(Hash, A); |
| hashing::detail::stable_hash_append(Hash, B); |
| return Hash; |
| } |
| |
| inline stable_hash stable_hash_combine(stable_hash A, stable_hash B, |
| stable_hash C) { |
| stable_hash Hash = hashing::detail::FNV_OFFSET_64; |
| hashing::detail::stable_hash_append(Hash, A); |
| hashing::detail::stable_hash_append(Hash, B); |
| hashing::detail::stable_hash_append(Hash, C); |
| return Hash; |
| } |
| |
| inline stable_hash stable_hash_combine(stable_hash A, stable_hash B, |
| stable_hash C, stable_hash D) { |
| stable_hash Hash = hashing::detail::FNV_OFFSET_64; |
| hashing::detail::stable_hash_append(Hash, A); |
| hashing::detail::stable_hash_append(Hash, B); |
| hashing::detail::stable_hash_append(Hash, C); |
| hashing::detail::stable_hash_append(Hash, D); |
| return Hash; |
| } |
| |
| /// Compute a stable_hash for a sequence of values. |
| /// |
| /// This hashes a sequence of values. It produces the same stable_hash as |
| /// 'stable_hash_combine(a, b, c, ...)', but can run over arbitrary sized |
| /// sequences and is significantly faster given pointers and types which |
| /// can be hashed as a sequence of bytes. |
| template <typename InputIteratorT> |
| stable_hash stable_hash_combine_range(InputIteratorT First, |
| InputIteratorT Last) { |
| stable_hash Hash = hashing::detail::FNV_OFFSET_64; |
| for (auto I = First; I != Last; ++I) |
| hashing::detail::stable_hash_append(Hash, *I); |
| return Hash; |
| } |
| |
| inline stable_hash stable_hash_combine_array(const stable_hash *P, size_t C) { |
| stable_hash Hash = hashing::detail::FNV_OFFSET_64; |
| for (size_t I = 0; I < C; ++I) |
| hashing::detail::stable_hash_append(Hash, P[I]); |
| return Hash; |
| } |
| |
| inline stable_hash stable_hash_combine_string(const StringRef &S) { |
| return stable_hash_combine_range(S.begin(), S.end()); |
| } |
| |
| inline stable_hash stable_hash_combine_string(const char *C) { |
| stable_hash Hash = hashing::detail::FNV_OFFSET_64; |
| while (*C) |
| hashing::detail::stable_hash_append(Hash, *(C++)); |
| return Hash; |
| } |
| |
| } // namespace llvm |
| |
| #endif |