From bfd7f7ae56a4f08f04a37454848680203da9a0e7 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Thu, 5 Nov 2026 15:41:39 +0000 Subject: [PATCH] Force inlining of `Hasher::HashSizedBytes` (#8092) This routine is large enough that it sometimes exceeds the inlining threshold. However, when out-of-line, it forces `Hasher` to be spilled to the stack in addition to the register pressure of the out-of-line call. The performance here is really engineered around it being inlined, so force the issue with an attribute. This also requires force inlining of the wrappers that bottom out at this routine, or we'd just move the problem up one layer without fully solving it. I don't have specific numbers for this, but it seems like a generally good change to ensure consistent performance here. Assisted-by: Antigravity with Gemini --- common/hashing.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/common/hashing.h b/common/hashing.h index 828e41fcd9d4..7b41f87176be 100644 --- a/common/hashing.h +++ b/common/hashing.h @@ -487,7 +487,8 @@ inline auto CarbonHashValue(llvm::ArrayRef values) -> HashCode { return static_cast(hasher); } -inline auto CarbonHashValue(llvm::ArrayRef bytes) -> HashCode { +[[clang::always_inline]] inline auto CarbonHashValue( + llvm::ArrayRef bytes) -> HashCode { Hasher hasher; hasher.HashSizedBytes(bytes); return static_cast(hasher); @@ -495,16 +496,19 @@ inline auto CarbonHashValue(llvm::ArrayRef bytes) -> HashCode { // Hashing implementation for `llvm::StringRef`. We forward all the other // string-like types that support heterogeneous lookup to this one. -inline auto CarbonHashValue(llvm::StringRef value) -> HashCode { +[[clang::always_inline]] inline auto CarbonHashValue(llvm::StringRef value) + -> HashCode { return CarbonHashValue(llvm::ArrayRef( reinterpret_cast(value.data()), value.size())); } -inline auto CarbonHashValue(std::string_view value) -> HashCode { +[[clang::always_inline]] inline auto CarbonHashValue(std::string_view value) + -> HashCode { return CarbonHashValue(llvm::StringRef(value.data(), value.size())); } -inline auto CarbonHashValue(const std::string& value) -> HashCode { +[[clang::always_inline]] inline auto CarbonHashValue(const std::string& value) + -> HashCode { return CarbonHashValue(llvm::StringRef(value.data(), value.size())); } @@ -607,7 +611,7 @@ concept CanHashAsRawDataType = std::same_as || // overloads, either here, or via ADL. Note that similar to // `HasCarbonHashValue`, this must not be moved above any of those overloads. template -inline auto DispatchImpl(const T& value) -> HashCode { +[[clang::always_inline]] inline auto DispatchImpl(const T& value) -> HashCode { if constexpr (HasCarbonHashValue) { // 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 @@ -638,7 +642,7 @@ inline auto DispatchImpl(const T& value) -> HashCode { } // namespace InternalHashDispatch template -inline auto HashValue(const T& value) -> HashCode { +[[clang::always_inline]] inline auto HashValue(const T& value) -> HashCode { return InternalHashDispatch::DispatchImpl(value); } @@ -931,7 +935,8 @@ inline auto Hasher::HashRaw(const T& value) -> void { HashSizedBytesLarge(llvm::ArrayRef(data_ptr, sizeof(T))); } -inline auto Hasher::HashSizedBytes(llvm::ArrayRef bytes) -> void { +[[clang::always_inline]] inline auto Hasher::HashSizedBytes( + llvm::ArrayRef bytes) -> void { const std::byte* data_ptr = bytes.data(); const ssize_t size = bytes.size();