[turboshaft] faster hash for GVN

Bug: v8:12783
Change-Id: I97f6a28bfef7c9aed679c84f33d60a71cf467718
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3859327
Reviewed-by: Darius Mercadier <dmercadier@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82865}
This commit is contained in:
Tobias Tebbi 2022-08-30 17:35:22 +02:00 committed by V8 LUCI CQ
parent f6a1f55c3b
commit 9bbc13bd40
5 changed files with 101 additions and 13 deletions

View File

@ -2863,6 +2863,7 @@ filegroup(
"src/compiler/turboshaft/decompression-optimization.cc",
"src/compiler/turboshaft/decompression-optimization.h",
"src/compiler/turboshaft/deopt-data.h",
"src/compiler/turboshaft/fast-hash.h",
"src/compiler/turboshaft/graph-builder.cc",
"src/compiler/turboshaft/graph-builder.h",
"src/compiler/turboshaft/graph.cc",

View File

@ -2988,6 +2988,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/assembler.h",
"src/compiler/turboshaft/decompression-optimization.h",
"src/compiler/turboshaft/deopt-data.h",
"src/compiler/turboshaft/fast-hash.h",
"src/compiler/turboshaft/graph-builder.h",
"src/compiler/turboshaft/graph-visualizer.h",
"src/compiler/turboshaft/graph.h",

View File

@ -0,0 +1,73 @@
// Copyright 2022 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.
#ifndef V8_COMPILER_TURBOSHAFT_FAST_HASH_H_
#define V8_COMPILER_TURBOSHAFT_FAST_HASH_H_
#include <tuple>
#include "src/base/functional.h"
#include "src/base/vector.h"
namespace v8::internal::compiler::turboshaft {
// fast_hash_combine() / fast_hash_value() produce a bad but very fast to
// compute hash, intended for hash-tables and only usable for data that is
// sufficiently random already and has high variance in their low bits.
V8_INLINE size_t fast_hash_combine() { return 0u; }
V8_INLINE size_t fast_hash_combine(size_t acc) { return acc; }
V8_INLINE size_t fast_hash_combine(size_t acc, size_t value) {
return 17 * acc + value;
}
template <typename T, typename... Ts>
V8_INLINE size_t fast_hash_combine(T const& v, Ts const&... vs);
template <class T>
struct fast_hash {
size_t operator()(const T& v) {
if constexpr (std::is_enum<T>::value) {
return static_cast<size_t>(v);
} else {
return base::hash<T>()(v);
}
}
};
template <class... Ts>
struct fast_hash<std::tuple<Ts...>> {
size_t operator()(const std::tuple<Ts...>& v) {
return impl(v, std::make_index_sequence<sizeof...(Ts)>());
}
template <size_t... I>
V8_INLINE size_t impl(std::tuple<Ts...> const& v, std::index_sequence<I...>) {
return fast_hash_combine(std::get<I>(v)...);
}
};
template <typename T, typename... Ts>
V8_INLINE size_t fast_hash_combine(T const& v, Ts const&... vs) {
return fast_hash_combine(fast_hash_combine(vs...), fast_hash<T>()(v));
}
template <typename Iterator>
V8_INLINE size_t fast_hash_range(Iterator first, Iterator last) {
size_t acc = 0;
for (; first != last; ++first) {
acc = fast_hash_combine(acc, *first);
}
return acc;
}
template <typename T>
struct fast_hash<base::Vector<T>> {
V8_INLINE size_t operator()(base::Vector<T> v) {
return fast_hash_range(v.begin(), v.end());
}
};
} // namespace v8::internal::compiler::turboshaft
#endif // V8_COMPILER_TURBOSHAFT_FAST_HASH_H_

View File

@ -24,6 +24,7 @@
#include "src/codegen/machine-type.h"
#include "src/common/globals.h"
#include "src/compiler/globals.h"
#include "src/compiler/turboshaft/fast-hash.h"
#include "src/compiler/turboshaft/utils.h"
#include "src/compiler/write-barrier-kind.h"
#include "src/zone/zone.h"
@ -177,7 +178,10 @@ class OpIndex {
static constexpr uint32_t kTurbofanNodeIdFlag = 1;
};
V8_INLINE size_t hash_value(OpIndex op) { return op.id(); }
template <>
struct fast_hash<OpIndex> {
V8_INLINE size_t operator()(OpIndex op) { return op.id(); }
};
// `BlockIndex` is the index of a bound block.
// A dominating block always has a smaller index.
@ -203,7 +207,10 @@ class BlockIndex {
uint32_t id_;
};
V8_INLINE size_t hash_value(BlockIndex b) { return b.id(); }
template <>
struct fast_hash<BlockIndex> {
V8_INLINE size_t operator()(BlockIndex op) { return op.id(); }
};
std::ostream& operator<<(std::ostream& os, BlockIndex b);
std::ostream& operator<<(std::ostream& os, const Block* b);
@ -419,7 +426,7 @@ struct OperationT : Operation {
derived_this().options() == other.derived_this().options();
}
size_t hash_value() const {
return base::hash_combine(opcode, derived_this().inputs(),
return fast_hash_combine(opcode, derived_this().inputs(),
derived_this().options());
}
@ -1154,17 +1161,17 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kWord32:
case Kind::kWord64:
case Kind::kTaggedIndex:
return base::hash_combine(kind, storage.integral);
return fast_hash_combine(opcode, kind, storage.integral);
case Kind::kFloat32:
return base::hash_combine(kind, storage.float32);
return fast_hash_combine(opcode, kind, storage.float32);
case Kind::kFloat64:
case Kind::kNumber:
return base::hash_combine(kind, storage.float64);
return fast_hash_combine(opcode, kind, storage.float64);
case Kind::kExternal:
return base::hash_combine(kind, storage.external.address());
return fast_hash_combine(opcode, kind, storage.external.address());
case Kind::kHeapObject:
case Kind::kCompressedHeapObject:
return base::hash_combine(kind, storage.handle.address());
return fast_hash_combine(opcode, kind, storage.handle.address());
}
}
bool operator==(const ConstantOp& other) const {
@ -1563,9 +1570,7 @@ struct SwitchOp : FixedArityOperationT<1, SwitchOp> {
Case(int32_t value, Block* destination)
: value(value), destination(destination) {}
friend size_t hash_value(Case v) {
return base::hash_combine(v.value, v.destination);
}
bool operator==(const Case& other) const {
return value == other.value && destination == other.destination;
}
@ -1583,6 +1588,13 @@ struct SwitchOp : FixedArityOperationT<1, SwitchOp> {
auto options() const { return std::tuple{cases, default_case}; }
};
template <>
struct fast_hash<SwitchOp::Case> {
size_t operator()(SwitchOp::Case v) {
return fast_hash_combine(v.value, v.destination);
}
};
// Tuples are only used to lower operations with multiple outputs.
// `TupleOp` should be folded away by subsequent `ProjectionOp`s.
struct TupleOp : OperationT<TupleOp> {

View File

@ -8,6 +8,7 @@
#include "src/base/logging.h"
#include "src/base/vector.h"
#include "src/compiler/turboshaft/assembler.h"
#include "src/compiler/turboshaft/fast-hash.h"
#include "src/compiler/turboshaft/graph.h"
#include "src/compiler/turboshaft/operations.h"
#include "src/utils/utils.h"
@ -239,7 +240,7 @@ class ValueNumberingAssembler : public Assembler {
size_t ComputeHash(const Op& op) {
size_t hash = op.hash_value();
if (same_block_only) {
hash = base::hash_combine(current_block()->index(), hash);
hash = fast_hash_combine(current_block()->index(), hash);
}
if (V8_UNLIKELY(hash == 0)) return 1;
return hash;