[base] allow inlining of hash_combine to improve performance

This improved Turboshaft value numbering performance
significantly in local testing.

Change-Id: I8b8c8e3a67da9b83b57efc34c08ca693e84d9076
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3852486
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82708}
This commit is contained in:
Tobias Tebbi 2022-08-24 19:21:58 +02:00 committed by V8 LUCI CQ
parent a084d3e594
commit d75a0eed1c
4 changed files with 83 additions and 116 deletions

View File

@ -607,7 +607,6 @@ filegroup(
"src/base/file-utils.h",
"src/base/flags.h",
"src/base/free_deleter.h",
"src/base/functional.cc",
"src/base/functional.h",
"src/base/hashmap-entry.h",
"src/base/hashmap.h",

View File

@ -5430,7 +5430,6 @@ v8_component("v8_libbase") {
"src/base/file-utils.h",
"src/base/flags.h",
"src/base/free_deleter.h",
"src/base/functional.cc",
"src/base/functional.h",
"src/base/hashmap-entry.h",
"src/base/hashmap.h",

View File

@ -1,110 +0,0 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This also contains public domain code from MurmurHash. From the
// MurmurHash header:
//
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
#include "src/base/functional.h"
#include <limits>
#include "src/base/bits.h"
namespace v8 {
namespace base {
namespace {
// Thomas Wang, Integer Hash Functions.
// https://gist.github.com/badboy/6267743
template <typename T>
V8_INLINE size_t hash_value_unsigned(T v) {
switch (sizeof(T)) {
case 4: {
// "32 bit Mix Functions"
v = ~v + (v << 15); // v = (v << 15) - v - 1;
v = v ^ (v >> 12);
v = v + (v << 2);
v = v ^ (v >> 4);
v = v * 2057; // v = (v + (v << 3)) + (v << 11);
v = v ^ (v >> 16);
return static_cast<size_t>(v);
}
case 8: {
switch (sizeof(size_t)) {
case 4: {
// "64 bit to 32 bit Hash Functions"
v = ~v + (v << 18); // v = (v << 18) - v - 1;
v = v ^ (v >> 31);
v = v * 21; // v = (v + (v << 2)) + (v << 4);
v = v ^ (v >> 11);
v = v + (v << 6);
v = v ^ (v >> 22);
return static_cast<size_t>(v);
}
case 8: {
// "64 bit Mix Functions"
v = ~v + (v << 21); // v = (v << 21) - v - 1;
v = v ^ (v >> 24);
v = (v + (v << 3)) + (v << 8); // v * 265
v = v ^ (v >> 14);
v = (v + (v << 2)) + (v << 4); // v * 21
v = v ^ (v >> 28);
v = v + (v << 31);
return static_cast<size_t>(v);
}
}
}
}
UNREACHABLE();
}
} // namespace
// This code was taken from MurmurHash.
size_t hash_combine(size_t seed, size_t value) {
#if V8_HOST_ARCH_32_BIT
const uint32_t c1 = 0xCC9E2D51;
const uint32_t c2 = 0x1B873593;
value *= c1;
value = bits::RotateRight32(value, 15);
value *= c2;
seed ^= value;
seed = bits::RotateRight32(seed, 13);
seed = seed * 5 + 0xE6546B64;
#else
const uint64_t m = uint64_t{0xC6A4A7935BD1E995};
const uint32_t r = 47;
value *= m;
value ^= value >> r;
value *= m;
seed ^= value;
seed *= m;
#endif // V8_HOST_ARCH_32_BIT
return seed;
}
size_t hash_value(unsigned int v) { return hash_value_unsigned(v); }
size_t hash_value(unsigned long v) { // NOLINT(runtime/int)
return hash_value_unsigned(v);
}
size_t hash_value(unsigned long long v) { // NOLINT(runtime/int)
return hash_value_unsigned(v);
}
} // namespace base
} // namespace v8

View File

@ -15,6 +15,7 @@
#include <utility>
#include "src/base/base-export.h"
#include "src/base/bits.h"
#include "src/base/macros.h"
namespace v8 {
@ -66,10 +67,80 @@ namespace base {
template <typename>
struct hash;
// Thomas Wang, Integer Hash Functions.
// https://gist.github.com/badboy/6267743
template <typename T>
V8_INLINE size_t hash_value_unsigned_impl(T v) {
switch (sizeof(T)) {
case 4: {
// "32 bit Mix Functions"
v = ~v + (v << 15); // v = (v << 15) - v - 1;
v = v ^ (v >> 12);
v = v + (v << 2);
v = v ^ (v >> 4);
v = v * 2057; // v = (v + (v << 3)) + (v << 11);
v = v ^ (v >> 16);
return static_cast<size_t>(v);
}
case 8: {
switch (sizeof(size_t)) {
case 4: {
// "64 bit to 32 bit Hash Functions"
v = ~v + (v << 18); // v = (v << 18) - v - 1;
v = v ^ (v >> 31);
v = v * 21; // v = (v + (v << 2)) + (v << 4);
v = v ^ (v >> 11);
v = v + (v << 6);
v = v ^ (v >> 22);
return static_cast<size_t>(v);
}
case 8: {
// "64 bit Mix Functions"
v = ~v + (v << 21); // v = (v << 21) - v - 1;
v = v ^ (v >> 24);
v = (v + (v << 3)) + (v << 8); // v * 265
v = v ^ (v >> 14);
v = (v + (v << 2)) + (v << 4); // v * 21
v = v ^ (v >> 28);
v = v + (v << 31);
return static_cast<size_t>(v);
}
}
}
}
UNREACHABLE();
}
V8_INLINE size_t hash_combine() { return 0u; }
V8_INLINE size_t hash_combine(size_t seed) { return seed; }
V8_BASE_EXPORT size_t hash_combine(size_t seed, size_t value);
// This code was taken from MurmurHash.
V8_INLINE size_t hash_combine(size_t seed, size_t value) {
#if V8_HOST_ARCH_32_BIT
const uint32_t c1 = 0xCC9E2D51;
const uint32_t c2 = 0x1B873593;
value *= c1;
value = bits::RotateRight32(value, 15);
value *= c2;
seed ^= value;
seed = bits::RotateRight32(seed, 13);
seed = seed * 5 + 0xE6546B64;
#else
const uint64_t m = uint64_t{0xC6A4A7935BD1E995};
const uint32_t r = 47;
value *= m;
value ^= value >> r;
value *= m;
seed ^= value;
seed *= m;
#endif // V8_HOST_ARCH_32_BIT
return seed;
}
template <typename T, typename... Ts>
V8_INLINE size_t hash_combine(T const& v, Ts const&... vs) {
return hash_combine(hash_combine(vs...), hash<T>()(v));
@ -93,9 +164,17 @@ V8_BASE_HASH_VALUE_TRIVIAL(unsigned char)
V8_BASE_HASH_VALUE_TRIVIAL(unsigned short) // NOLINT(runtime/int)
#undef V8_BASE_HASH_VALUE_TRIVIAL
V8_BASE_EXPORT size_t hash_value(unsigned int);
V8_BASE_EXPORT size_t hash_value(unsigned long); // NOLINT(runtime/int)
V8_BASE_EXPORT size_t hash_value(unsigned long long); // NOLINT(runtime/int)
V8_INLINE size_t hash_value(unsigned int v) {
return hash_value_unsigned_impl(v);
}
V8_INLINE size_t hash_value(unsigned long v) { // NOLINT(runtime/int)
return hash_value_unsigned_impl(v);
}
V8_INLINE size_t hash_value(unsigned long long v) { // NOLINT(runtime/int)
return hash_value_unsigned_impl(v);
}
#define V8_BASE_HASH_VALUE_SIGNED(type) \
V8_INLINE size_t hash_value(signed type v) { \