mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:20:11 +01:00
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:
@@ -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,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
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -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"
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "common/hashing_llvm.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace {
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user