common: Decouple LLVM hashing dependencies from common/hashing.h (#7646)

- Move formatted printing to `hashing.cpp` instead of `hashing.h`
- Separate APInt and APFloat hashing specializations into a new
`hashing_llvm.h`
- Update toolchain/base dependencies and include sites that hash LLVM
data types to include `hashing_llvm.h`

Combined, this reduces the transitive includes caused by `hashing.h`.

Assisted-by: Antigravity with Gemini
This commit is contained in:
Chandler Carruth
2026-08-26 00:41:51 +00:00
committed by GitHub
parent c7dcc50768
commit 95fc6fae22
12 changed files with 103 additions and 44 deletions
+13
View File
@@ -342,12 +342,22 @@ cc_library(
],
)
cc_library(
name = "hashing_llvm",
hdrs = ["hashing_llvm.h"],
deps = [
":hashing",
"@llvm-project//llvm:Support",
],
)
cc_test(
name = "hashing_test",
size = "small",
srcs = ["hashing_test.cpp"],
deps = [
":hashing",
":hashing_llvm",
":raw_string_ostream",
"//testing/base:gtest_main",
"@googletest//:gtest",
@@ -384,6 +394,7 @@ cc_test(
size = "small",
srcs = ["hashtable_key_context_test.cpp"],
deps = [
":hashing_llvm",
":hashtable_key_context",
"//testing/base:gtest_main",
"@googletest//:gtest",
@@ -460,6 +471,7 @@ cc_test(
":raw_hashtable_test_helpers",
"//testing/base:gtest_main",
"@googletest//:gtest",
"@llvm-project//llvm:Support",
],
)
@@ -648,6 +660,7 @@ cc_test(
":set",
"//testing/base:gtest_main",
"@googletest//:gtest",
"@llvm-project//llvm:Support",
],
)
+6
View File
@@ -6,8 +6,14 @@
#include <cstddef>
#include "llvm/Support/FormatVariadic.h"
namespace Carbon {
auto HashCode::Print(llvm::raw_ostream& out) const -> void {
out << llvm::formatv("{0:x16}", value_);
}
auto Hasher::HashSizedBytesLarge(llvm::ArrayRef<std::byte> bytes) -> void {
const std::byte* data_ptr = bytes.data();
const ssize_t size = bytes.size();
+26 -39
View File
@@ -13,12 +13,9 @@
#include "common/check.h"
#include "common/ostream.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatVariadic.h"
#ifdef __ARM_ACLE
#include <arm_acle.h>
@@ -72,9 +69,7 @@ class HashCode : public Printable<HashCode> {
// other recursive hashing where that is needed or more efficient.
explicit operator uint64_t() const { return value_; }
auto Print(llvm::raw_ostream& out) const -> void {
out << llvm::formatv("{0:x16}", value_);
}
auto Print(llvm::raw_ostream& out) const -> void;
private:
uint64_t value_ = 0;
@@ -527,30 +522,6 @@ inline auto CarbonHashValue(const T (&arg)[N], uint64_t seed) -> HashCode {
return CarbonHashValue(llvm::ArrayRef(arg), seed);
}
inline auto CarbonHashValue(llvm::APInt value, uint64_t seed) -> HashCode {
Hasher hasher(seed);
if (LLVM_LIKELY(value.isSingleWord())) {
hasher.Hash(value.getBitWidth(), value.getZExtValue());
} else {
hasher.HashRaw(value.getBitWidth());
hasher.HashSizedBytes(
llvm::ArrayRef(value.getRawData(), value.getNumWords()));
}
return static_cast<HashCode>(hasher);
}
inline auto CarbonHashValue(llvm::APFloat value, uint64_t seed) -> HashCode {
Hasher hasher(seed);
// Hashing floating point numbers is complex and depends on the specific
// internal semantics of `APFloat`, so delegate to the LLVM hashing framework
// here. We re-hash the result to mix in our seed. All of this is a bit
// inefficient, and we can revisit this to provide a dedicated implementation
// if it becomes a bottleneck.
using llvm::hash_value;
hasher.HashRaw(hash_value(value));
return static_cast<HashCode>(hasher);
}
template <typename... Ts>
inline auto CarbonHashValue(const std::tuple<Ts...>& value, uint64_t seed)
-> HashCode {
@@ -567,6 +538,14 @@ inline auto CarbonHashValue(const std::pair<T, U>& value, uint64_t seed)
return static_cast<HashCode>(hasher);
}
// Extension point for types defined outside of Carbon that cannot be found by
// ADL in their own namespace and cannot be declared before this point.
template <typename T>
struct CustomHashValue;
template <typename T>
concept HasCustomHashValue = requires { CustomHashValue<T>::Hash; };
// Implementation detail predicate to detect if there is a `CarbonHashValue`
// overload available for a particular type, either in this namespace or found
// via ADL. Note that this should not be moved above any overloads.
@@ -618,14 +597,19 @@ concept CanHashAsRawDataType = std::same_as<T, std::nullptr_t> ||
// `HasCarbonHashValue`, this must not be moved above any of those overloads.
template <typename T>
inline auto DispatchImpl(const T& value, uint64_t seed) -> HashCode {
// If we have an explicit overload for `CarbonHashValue`, call it. This may be
// provided above or via ADL, and is preferred as it represents an explicit
// request for how the type is hashed.
if constexpr (HasCarbonHashValue<T>) {
// If we have an explicit overload for `CarbonHashValue`, call it. This may
// be provided above or via ADL, and is preferred as it represents an
// explicit request for how the type is hashed.
return CarbonHashValue(value, seed);
} else if constexpr (HasCustomHashValue<T>) {
// If we have an explicit specialization for `CustomHashValue`, call it.
// This is a fallback explicit hashing path that doesn't require ADL or
// being in this header.
return CustomHashValue<T>::Hash(value, seed);
} else if constexpr (CanHashAsRawDataType<T>) {
// There was no explicit overload to call, but the type allows us to hash it
// as raw data, do so.
// There was no explicit overload or specialization to call, but the type
// allows us to hash it as raw data, do so.
Hasher hasher(seed);
hasher.HashRaw(MapToRawDataType(value));
return static_cast<HashCode>(hasher);
@@ -813,11 +797,13 @@ inline auto Hasher::Hash(const Ts&... values) -> void {
using InternalHashDispatch::CanHashAsRawDataType;
using InternalHashDispatch::HasCarbonHashValue;
using InternalHashDispatch::HasCustomHashValue;
using InternalHashDispatch::MapToRawDataType;
// Special-case a single element tuple that we will hash as raw data.
if constexpr (sizeof...(Ts) == 1 && (... && (!HasCarbonHashValue<Ts> &&
CanHashAsRawDataType<Ts>))) {
if constexpr (sizeof...(Ts) == 1 &&
(... && (!HasCarbonHashValue<Ts> && !HasCustomHashValue<Ts> &&
CanHashAsRawDataType<Ts>))) {
HashRaw(MapToRawDataType(values)...);
return;
}
@@ -830,7 +816,7 @@ inline auto Hasher::Hash(const Ts&... values) -> void {
// a little bit wasteful in some cases, collapsing down to a flat array of
// 64-bit integers is more efficient to hash.
auto map_value = []<typename T>(const T& value) -> uint64_t {
if constexpr (HasCarbonHashValue<T>) {
if constexpr (HasCarbonHashValue<T> || HasCustomHashValue<T>) {
// Use the top-level `HashValue` to re-dispatch to the custom
// implementation with a fixed seed.
return static_cast<uint64_t>(HashValue(value));
@@ -866,11 +852,12 @@ template <typename T>
inline auto Hasher::HashArray(llvm::ArrayRef<T> values) -> void {
using InternalHashDispatch::CanHashAsRawDataType;
using InternalHashDispatch::HasCarbonHashValue;
using InternalHashDispatch::HasCustomHashValue;
// This logic similarly mirrors `InternalHashDispatch::DispatchImpl`, but is
// specialized here to allow us to efficiently process the array when it
// *doesn't* require recursive hashing.
if constexpr (HasCarbonHashValue<T>) {
if constexpr (HasCarbonHashValue<T> || HasCustomHashValue<T>) {
// Use a trivial loop to give consistent behavior for arrays requiring
// recursive hashing. This isn't terribly efficient, but if clients care
// they should specialize the entire hashing operation. For simple, tiny
+47
View File
@@ -0,0 +1,47 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_COMMON_HASHING_LLVM_H_
#define CARBON_COMMON_HASHING_LLVM_H_
#include "common/hashing.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Hashing.h"
namespace Carbon::InternalHashDispatch {
template <>
struct CustomHashValue<llvm::APInt> {
static auto Hash(llvm::APInt value, uint64_t seed) -> HashCode {
Hasher hasher(seed);
if (LLVM_LIKELY(value.isSingleWord())) {
hasher.Hash(value.getBitWidth(), value.getZExtValue());
} else {
hasher.HashRaw(value.getBitWidth());
hasher.HashSizedBytes(
llvm::ArrayRef(value.getRawData(), value.getNumWords()));
}
return static_cast<HashCode>(hasher);
}
};
template <>
struct CustomHashValue<llvm::APFloat> {
static auto Hash(llvm::APFloat value, uint64_t seed) -> HashCode {
Hasher hasher(seed);
// Hashing floating point numbers is complex and depends on the specific
// internal semantics of `APFloat`, so delegate to the LLVM hashing
// framework here. We re-hash the result to mix in our seed. All of this is
// a bit inefficient, and we can revisit this to provide a dedicated
// implementation if it becomes a bottleneck.
using llvm::hash_value;
hasher.HashRaw(hash_value(value));
return static_cast<HashCode>(hasher);
}
};
} // namespace Carbon::InternalHashDispatch
#endif // CARBON_COMMON_HASHING_LLVM_H_
+1
View File
@@ -13,6 +13,7 @@
#include <type_traits>
#include <utility>
#include "common/hashing_llvm.h"
#include "common/raw_string_ostream.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/StringExtras.h"
+2
View File
@@ -7,6 +7,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "common/hashing_llvm.h"
namespace Carbon {
namespace {
+3 -5
View File
@@ -24,7 +24,6 @@ cc_library(
":value_store",
":yaml",
"//common:check",
"//common:hashing",
"//common:set",
"@llvm-project//llvm:Support",
],
@@ -55,6 +54,7 @@ cc_test(
":shared_value_stores",
":value_ids",
":value_store",
"//common:hashing_llvm",
"//testing/base:gtest_main",
"@googletest//:gtest",
"@llvm-project//llvm:Support",
@@ -67,7 +67,6 @@ cc_library(
hdrs = ["clang_invocation.h"],
deps = [
":install_paths",
"//common:check",
"//common:string_helpers",
"//toolchain/diagnostics:emitter",
"@llvm-project//clang:basic",
@@ -92,9 +91,6 @@ cc_library(
cc_library(
name = "for_each_macro",
hdrs = ["for_each_macro.h"],
deps = [
"@llvm-project//llvm:Support",
],
)
cc_library(
@@ -292,6 +288,7 @@ cc_library(
":value_store",
":yaml",
"//common:check",
"//common:hashing_llvm",
"//common:hashtable_key_context",
"//common:ostream",
"//common:set",
@@ -356,6 +353,7 @@ cc_library(
":value_ids",
":value_store",
":yaml",
"//common:hashing_llvm",
"@llvm-project//llvm:Support",
],
)
@@ -9,6 +9,7 @@
#include <string>
#include "common/hashing_llvm.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/StringRef.h"
#include "toolchain/base/canonical_value_store_impl.h"
+1
View File
@@ -7,6 +7,7 @@
#include <algorithm>
#include <string>
#include "common/hashing_llvm.h"
#include "toolchain/base/canonical_value_store_impl.h"
#include "toolchain/base/value_store_impl.h"
+1
View File
@@ -6,6 +6,7 @@
#define CARBON_TOOLCHAIN_BASE_INT_H_
#include "common/check.h"
#include "common/hashing_llvm.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallVector.h"
#include "toolchain/base/canonical_value_store.h"
+1
View File
@@ -4,6 +4,7 @@
#include "toolchain/base/shared_value_stores.h"
#include "common/hashing_llvm.h"
#include "toolchain/base/canonical_value_store_impl.h"
#include "toolchain/base/value_store_impl.h"
+1
View File
@@ -5,6 +5,7 @@
#ifndef CARBON_TOOLCHAIN_BASE_SHARED_VALUE_STORES_H_
#define CARBON_TOOLCHAIN_BASE_SHARED_VALUE_STORES_H_
#include "common/hashing_llvm.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/StringRef.h"
#include "toolchain/base/canonical_value_store.h"