tint: Castable - optimize IsAnyOf()
`HashCodeOf()` sets two bits in the mask to `1`. We can check for two bits set, after masking, to quickly eliminate impossible Is() tests. Change-Id: I8d9c1ece87b714e83bd292d02e02274d42e143ef Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/92664 Commit-Queue: Ben Clayton <bclayton@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
cdcc85973b
commit
e5d337171a
|
@ -159,7 +159,7 @@ struct TypeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns a compile-time hashcode for the type `T`.
|
/// @returns a compile-time hashcode for the type `T`.
|
||||||
/// @note the returned hashcode will have at most 2 bits set, as the hashes
|
/// @note the returned hashcode will have exactly 2 bits set, as the hashes
|
||||||
/// are expected to be used in bloom-filters which will quickly saturate when
|
/// are expected to be used in bloom-filters which will quickly saturate when
|
||||||
/// multiple hashcodes are bitwise-or'd together.
|
/// multiple hashcodes are bitwise-or'd together.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -176,7 +176,8 @@ struct TypeInfo {
|
||||||
#endif
|
#endif
|
||||||
constexpr uint32_t bit_a = (crc & 63);
|
constexpr uint32_t bit_a = (crc & 63);
|
||||||
constexpr uint32_t bit_b = ((crc >> 6) & 63);
|
constexpr uint32_t bit_b = ((crc >> 6) & 63);
|
||||||
return (static_cast<HashCode>(1) << bit_a) | (static_cast<HashCode>(1) << bit_b);
|
constexpr uint32_t bit_c = (bit_a == bit_b) ? ((bit_a + 1) & 63) : bit_b;
|
||||||
|
return (static_cast<HashCode>(1) << bit_a) | (static_cast<HashCode>(1) << bit_c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the hashcode of the given type, bitwise-or'd with the hashcodes
|
/// @returns the hashcode of the given type, bitwise-or'd with the hashcodes
|
||||||
|
@ -221,17 +222,16 @@ struct TypeInfo {
|
||||||
if constexpr (kCount == 0) {
|
if constexpr (kCount == 0) {
|
||||||
return false;
|
return false;
|
||||||
} else if constexpr (kCount == 1) {
|
} else if constexpr (kCount == 1) {
|
||||||
return Is<std::tuple_element_t<0, TUPLE>>();
|
return Is(&Of<std::tuple_element_t<0, TUPLE>>());
|
||||||
} else if constexpr (kCount == 2) {
|
|
||||||
return Is<std::tuple_element_t<0, TUPLE>>() || Is<std::tuple_element_t<1, TUPLE>>();
|
|
||||||
} else if constexpr (kCount == 3) {
|
|
||||||
return Is<std::tuple_element_t<0, TUPLE>>() || Is<std::tuple_element_t<1, TUPLE>>() ||
|
|
||||||
Is<std::tuple_element_t<2, TUPLE>>();
|
|
||||||
} else {
|
} else {
|
||||||
// Optimization: Compare the object's hashcode to the bitwise-or of all
|
// Optimization: Compare the object's hashcode to the bitwise-or of all the tested
|
||||||
// the tested type's hashcodes. If there's no intersection of bits in
|
// type's hashcodes. If there's no intersection of bits in the two masks, then we can
|
||||||
// the two masks, then we can guarantee that the type is not in `TO`.
|
// guarantee that the type is not in `TO`.
|
||||||
if (full_hashcode & TypeInfo::CombinedHashCodeOfTuple<TUPLE>()) {
|
HashCode mask = full_hashcode & TypeInfo::CombinedHashCodeOfTuple<TUPLE>();
|
||||||
|
// HashCodeOf() ensures that two bits are always set for every hash, so we can quickly
|
||||||
|
// eliminate the bitmask where only one bit is set.
|
||||||
|
HashCode two_bits = mask & (mask - 1);
|
||||||
|
if (two_bits) {
|
||||||
// Possibly one of the types in `TUPLE`.
|
// Possibly one of the types in `TUPLE`.
|
||||||
// Split the search in two, and scan each block.
|
// Split the search in two, and scan each block.
|
||||||
static constexpr auto kMid = kCount / 2;
|
static constexpr auto kMid = kCount / 2;
|
||||||
|
@ -607,9 +607,14 @@ inline bool NonDefaultCases(T* object,
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Multiple cases.
|
// Multiple cases.
|
||||||
// Check the hashcode bits to see if there's any possibility of a case
|
// Check the hashcode bits to see if there's any possibility of a case matching in these
|
||||||
// matching in these cases. If there isn't, we can skip all these cases.
|
// cases. If there isn't, we can skip all these cases.
|
||||||
if (type->full_hashcode & TypeInfo::CombinedHashCodeOf<SwitchCaseType<CASES>...>()) {
|
TypeInfo::HashCode mask =
|
||||||
|
type->full_hashcode & TypeInfo::CombinedHashCodeOf<SwitchCaseType<CASES>...>();
|
||||||
|
// HashCodeOf() ensures that two bits are always set for every hash, so we can quickly
|
||||||
|
// eliminate the bitmask where only one bit is set.
|
||||||
|
TypeInfo::HashCode two_bits = mask & (mask - 1);
|
||||||
|
if (two_bits) {
|
||||||
// There's a possibility. We need to scan further.
|
// There's a possibility. We need to scan further.
|
||||||
// Split the cases into two, and recurse.
|
// Split the cases into two, and recurse.
|
||||||
constexpr size_t kMid = kNumCases / 2;
|
constexpr size_t kMid = kNumCases / 2;
|
||||||
|
|
Loading…
Reference in New Issue