mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-25 01:01:04 +00:00
Optimize Type::HashValue (#4707)
Incrementally compute the hash instead of collecting words Avoids allocating temporary space in a std::vector and std::u32string, and making three passes over all the hashed data. Switch to using std::vector to prevent processing duplicates instead of std::unordered_set: avoids an allocation/deletion every call to ComputeHashValue, and ends up faster due to much better cache behaviour and smaller constant-factor when searching the (generally very small) list. In my test case, made Type::HashValue go from 7.5% of compilation time to .5%
This commit is contained in:
parent
471428a04f
commit
a123632ed9
1
BUILD.gn
1
BUILD.gn
@ -448,6 +448,7 @@ static_library("spvtools") {
|
||||
"source/util/bit_vector.cpp",
|
||||
"source/util/bit_vector.h",
|
||||
"source/util/bitutils.h",
|
||||
"source/util/hash_combine.h",
|
||||
"source/util/hex_float.h",
|
||||
"source/util/ilist.h",
|
||||
"source/util/ilist_node.h",
|
||||
|
@ -224,6 +224,7 @@ set(SPIRV_SOURCES
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/bitutils.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/bit_vector.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/hash_combine.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/hex_float.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/make_unique.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/parse_number.h
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/util/hash_combine.h"
|
||||
#include "source/util/make_unique.h"
|
||||
#include "spirv/unified1/spirv.h"
|
||||
|
||||
@ -28,6 +29,7 @@ namespace spvtools {
|
||||
namespace opt {
|
||||
namespace analysis {
|
||||
|
||||
using spvtools::utils::hash_combine;
|
||||
using U32VecVec = std::vector<std::vector<uint32_t>>;
|
||||
|
||||
namespace {
|
||||
@ -182,23 +184,26 @@ bool Type::operator==(const Type& other) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Type::GetHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
if (!seen->insert(this).second) {
|
||||
return;
|
||||
size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const {
|
||||
// Linear search through a dense, cache coherent vector is faster than O(log
|
||||
// n) search in a complex data structure (eg std::set) for the generally small
|
||||
// number of nodes. It also skips the overhead of an new/delete per Type
|
||||
// (when inserting/removing from a set).
|
||||
if (std::find(seen->begin(), seen->end(), this) != seen->end()) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
words->push_back(kind_);
|
||||
seen->push_back(this);
|
||||
|
||||
hash = hash_combine(hash, uint32_t(kind_));
|
||||
for (const auto& d : decorations_) {
|
||||
for (auto w : d) {
|
||||
words->push_back(w);
|
||||
}
|
||||
hash = hash_combine(hash, d);
|
||||
}
|
||||
|
||||
switch (kind_) {
|
||||
#define DeclareKindCase(type) \
|
||||
case k##type: \
|
||||
As##type()->GetExtraHashWords(words, seen); \
|
||||
#define DeclareKindCase(type) \
|
||||
case k##type: \
|
||||
hash = As##type()->ComputeExtraStateHash(hash, seen); \
|
||||
break
|
||||
DeclareKindCase(Void);
|
||||
DeclareKindCase(Bool);
|
||||
@ -232,18 +237,13 @@ void Type::GetHashWords(std::vector<uint32_t>* words,
|
||||
break;
|
||||
}
|
||||
|
||||
seen->erase(this);
|
||||
seen->pop_back();
|
||||
return hash;
|
||||
}
|
||||
|
||||
size_t Type::HashValue() const {
|
||||
std::u32string h;
|
||||
std::vector<uint32_t> words;
|
||||
GetHashWords(&words);
|
||||
for (auto w : words) {
|
||||
h.push_back(w);
|
||||
}
|
||||
|
||||
return std::hash<std::u32string>()(h);
|
||||
SeenTypes seen;
|
||||
return ComputeHashValue(0, &seen);
|
||||
}
|
||||
|
||||
bool Integer::IsSameImpl(const Type* that, IsSameCache*) const {
|
||||
@ -258,10 +258,8 @@ std::string Integer::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Integer::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>*) const {
|
||||
words->push_back(width_);
|
||||
words->push_back(signed_);
|
||||
size_t Integer::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
|
||||
return hash_combine(hash, width_, signed_);
|
||||
}
|
||||
|
||||
bool Float::IsSameImpl(const Type* that, IsSameCache*) const {
|
||||
@ -275,9 +273,8 @@ std::string Float::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Float::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>*) const {
|
||||
words->push_back(width_);
|
||||
size_t Float::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
|
||||
return hash_combine(hash, width_);
|
||||
}
|
||||
|
||||
Vector::Vector(const Type* type, uint32_t count)
|
||||
@ -299,10 +296,11 @@ std::string Vector::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Vector::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
element_type_->GetHashWords(words, seen);
|
||||
words->push_back(count_);
|
||||
size_t Vector::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
// prefer form that doesn't require push/pop from stack: add state and
|
||||
// make tail call.
|
||||
hash = hash_combine(hash, count_);
|
||||
return element_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
Matrix::Matrix(const Type* type, uint32_t count)
|
||||
@ -324,10 +322,9 @@ std::string Matrix::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Matrix::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
element_type_->GetHashWords(words, seen);
|
||||
words->push_back(count_);
|
||||
size_t Matrix::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
hash = hash_combine(hash, count_);
|
||||
return element_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
Image::Image(Type* type, SpvDim dimen, uint32_t d, bool array, bool multisample,
|
||||
@ -362,16 +359,10 @@ std::string Image::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Image::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
sampled_type_->GetHashWords(words, seen);
|
||||
words->push_back(dim_);
|
||||
words->push_back(depth_);
|
||||
words->push_back(arrayed_);
|
||||
words->push_back(ms_);
|
||||
words->push_back(sampled_);
|
||||
words->push_back(format_);
|
||||
words->push_back(access_qualifier_);
|
||||
size_t Image::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
hash = hash_combine(hash, uint32_t(dim_), depth_, arrayed_, ms_, sampled_,
|
||||
uint32_t(format_), uint32_t(access_qualifier_));
|
||||
return sampled_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
bool SampledImage::IsSameImpl(const Type* that, IsSameCache* seen) const {
|
||||
@ -387,9 +378,8 @@ std::string SampledImage::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void SampledImage::GetExtraHashWords(
|
||||
std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
|
||||
image_type_->GetHashWords(words, seen);
|
||||
size_t SampledImage::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
return image_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
Array::Array(const Type* type, const Array::LengthInfo& length_info_arg)
|
||||
@ -422,11 +412,9 @@ std::string Array::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Array::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
element_type_->GetHashWords(words, seen);
|
||||
words->insert(words->end(), length_info_.words.begin(),
|
||||
length_info_.words.end());
|
||||
size_t Array::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
hash = hash_combine(hash, length_info_.words);
|
||||
return element_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
void Array::ReplaceElementType(const Type* type) { element_type_ = type; }
|
||||
@ -449,9 +437,8 @@ std::string RuntimeArray::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void RuntimeArray::GetExtraHashWords(
|
||||
std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
|
||||
element_type_->GetHashWords(words, seen);
|
||||
size_t RuntimeArray::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
return element_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
void RuntimeArray::ReplaceElementType(const Type* type) {
|
||||
@ -508,19 +495,14 @@ std::string Struct::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Struct::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
size_t Struct::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
for (auto* t : element_types_) {
|
||||
t->GetHashWords(words, seen);
|
||||
hash = t->ComputeHashValue(hash, seen);
|
||||
}
|
||||
for (const auto& pair : element_decorations_) {
|
||||
words->push_back(pair.first);
|
||||
for (const auto& d : pair.second) {
|
||||
for (auto w : d) {
|
||||
words->push_back(w);
|
||||
}
|
||||
}
|
||||
hash = hash_combine(hash, pair.first, pair.second);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool Opaque::IsSameImpl(const Type* that, IsSameCache*) const {
|
||||
@ -535,11 +517,8 @@ std::string Opaque::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Opaque::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>*) const {
|
||||
for (auto c : name_) {
|
||||
words->push_back(static_cast<char32_t>(c));
|
||||
}
|
||||
size_t Opaque::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
|
||||
return hash_combine(hash, name_);
|
||||
}
|
||||
|
||||
Pointer::Pointer(const Type* type, SpvStorageClass sc)
|
||||
@ -568,10 +547,9 @@ std::string Pointer::str() const {
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void Pointer::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
pointee_type_->GetHashWords(words, seen);
|
||||
words->push_back(storage_class_);
|
||||
size_t Pointer::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
hash = hash_combine(hash, uint32_t(storage_class_));
|
||||
return pointee_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
void Pointer::SetPointeeType(const Type* type) { pointee_type_ = type; }
|
||||
@ -605,12 +583,11 @@ std::string Function::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Function::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const {
|
||||
return_type_->GetHashWords(words, seen);
|
||||
size_t Function::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const {
|
||||
for (const auto* t : param_types_) {
|
||||
t->GetHashWords(words, seen);
|
||||
hash = t->ComputeHashValue(hash, seen);
|
||||
}
|
||||
return return_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
void Function::SetReturnType(const Type* type) { return_type_ = type; }
|
||||
@ -627,9 +604,8 @@ std::string Pipe::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void Pipe::GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>*) const {
|
||||
words->push_back(access_qualifier_);
|
||||
size_t Pipe::ComputeExtraStateHash(size_t hash, SeenTypes*) const {
|
||||
return hash_combine(hash, uint32_t(access_qualifier_));
|
||||
}
|
||||
|
||||
bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const {
|
||||
@ -652,11 +628,11 @@ std::string ForwardPointer::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void ForwardPointer::GetExtraHashWords(
|
||||
std::vector<uint32_t>* words, std::unordered_set<const Type*>* seen) const {
|
||||
words->push_back(target_id_);
|
||||
words->push_back(storage_class_);
|
||||
if (pointer_) pointer_->GetHashWords(words, seen);
|
||||
size_t ForwardPointer::ComputeExtraStateHash(size_t hash,
|
||||
SeenTypes* seen) const {
|
||||
hash = hash_combine(hash, target_id_, uint32_t(storage_class_));
|
||||
if (pointer_) hash = pointer_->ComputeHashValue(hash, seen);
|
||||
return hash;
|
||||
}
|
||||
|
||||
CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope,
|
||||
@ -680,12 +656,10 @@ std::string CooperativeMatrixNV::str() const {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void CooperativeMatrixNV::GetExtraHashWords(
|
||||
std::vector<uint32_t>* words, std::unordered_set<const Type*>* pSet) const {
|
||||
component_type_->GetHashWords(words, pSet);
|
||||
words->push_back(scope_id_);
|
||||
words->push_back(rows_id_);
|
||||
words->push_back(columns_id_);
|
||||
size_t CooperativeMatrixNV::ComputeExtraStateHash(size_t hash,
|
||||
SeenTypes* seen) const {
|
||||
hash = hash_combine(hash, scope_id_, rows_id_, columns_id_);
|
||||
return component_type_->ComputeHashValue(hash, seen);
|
||||
}
|
||||
|
||||
bool CooperativeMatrixNV::IsSameImpl(const Type* that,
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "source/latest_version_spirv_header.h"
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/util/small_vector.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
@ -67,6 +68,8 @@ class Type {
|
||||
public:
|
||||
typedef std::set<std::pair<const Pointer*, const Pointer*>> IsSameCache;
|
||||
|
||||
using SeenTypes = spvtools::utils::SmallVector<const Type*, 8>;
|
||||
|
||||
// Available subtypes.
|
||||
//
|
||||
// When adding a new derived class of Type, please add an entry to the enum.
|
||||
@ -155,21 +158,7 @@ class Type {
|
||||
// Returns the hash value of this type.
|
||||
size_t HashValue() const;
|
||||
|
||||
// Adds the necessary words to compute a hash value of this type to |words|.
|
||||
void GetHashWords(std::vector<uint32_t>* words) const {
|
||||
std::unordered_set<const Type*> seen;
|
||||
GetHashWords(words, &seen);
|
||||
}
|
||||
|
||||
// Adds the necessary words to compute a hash value of this type to |words|.
|
||||
void GetHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* seen) const;
|
||||
|
||||
// Adds necessary extra words for a subtype to calculate a hash value into
|
||||
// |words|.
|
||||
virtual void GetExtraHashWords(
|
||||
std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const = 0;
|
||||
size_t ComputeHashValue(size_t hash, SeenTypes* seen) const;
|
||||
|
||||
// A bunch of methods for casting this type to a given type. Returns this if the
|
||||
// cast can be done, nullptr otherwise.
|
||||
@ -205,6 +194,10 @@ class Type {
|
||||
DeclareCastMethod(RayQueryKHR)
|
||||
#undef DeclareCastMethod
|
||||
|
||||
protected:
|
||||
// Add any type-specific state to |hash| and returns new hash.
|
||||
virtual size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const = 0;
|
||||
|
||||
protected:
|
||||
// Decorations attached to this type. Each decoration is encoded as a vector
|
||||
// of uint32_t numbers. The first uint32_t number is the decoration value,
|
||||
@ -233,8 +226,7 @@ class Integer : public Type {
|
||||
uint32_t width() const { return width_; }
|
||||
bool IsSigned() const { return signed_; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -254,8 +246,7 @@ class Float : public Type {
|
||||
const Float* AsFloat() const override { return this; }
|
||||
uint32_t width() const { return width_; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -275,8 +266,7 @@ class Vector : public Type {
|
||||
Vector* AsVector() override { return this; }
|
||||
const Vector* AsVector() const override { return this; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -297,8 +287,7 @@ class Matrix : public Type {
|
||||
Matrix* AsMatrix() override { return this; }
|
||||
const Matrix* AsMatrix() const override { return this; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -328,8 +317,7 @@ class Image : public Type {
|
||||
SpvImageFormat format() const { return format_; }
|
||||
SpvAccessQualifier access_qualifier() const { return access_qualifier_; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -356,8 +344,7 @@ class SampledImage : public Type {
|
||||
|
||||
const Type* image_type() const { return image_type_; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -400,8 +387,7 @@ class Array : public Type {
|
||||
Array* AsArray() override { return this; }
|
||||
const Array* AsArray() const override { return this; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
void ReplaceElementType(const Type* element_type);
|
||||
|
||||
@ -423,8 +409,7 @@ class RuntimeArray : public Type {
|
||||
RuntimeArray* AsRuntimeArray() override { return this; }
|
||||
const RuntimeArray* AsRuntimeArray() const override { return this; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
void ReplaceElementType(const Type* element_type);
|
||||
|
||||
@ -460,8 +445,7 @@ class Struct : public Type {
|
||||
Struct* AsStruct() override { return this; }
|
||||
const Struct* AsStruct() const override { return this; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -492,8 +476,7 @@ class Opaque : public Type {
|
||||
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -513,8 +496,7 @@ class Pointer : public Type {
|
||||
Pointer* AsPointer() override { return this; }
|
||||
const Pointer* AsPointer() const override { return this; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
void SetPointeeType(const Type* type);
|
||||
|
||||
@ -540,8 +522,7 @@ class Function : public Type {
|
||||
const std::vector<const Type*>& param_types() const { return param_types_; }
|
||||
std::vector<const Type*>& param_types() { return param_types_; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>*) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
void SetReturnType(const Type* type);
|
||||
|
||||
@ -565,8 +546,7 @@ class Pipe : public Type {
|
||||
|
||||
SpvAccessQualifier access_qualifier() const { return access_qualifier_; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -593,8 +573,7 @@ class ForwardPointer : public Type {
|
||||
ForwardPointer* AsForwardPointer() override { return this; }
|
||||
const ForwardPointer* AsForwardPointer() const override { return this; }
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>* words,
|
||||
std::unordered_set<const Type*>* pSet) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
private:
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override;
|
||||
@ -617,8 +596,7 @@ class CooperativeMatrixNV : public Type {
|
||||
return this;
|
||||
}
|
||||
|
||||
void GetExtraHashWords(std::vector<uint32_t>*,
|
||||
std::unordered_set<const Type*>*) const override;
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override;
|
||||
|
||||
const Type* component_type() const { return component_type_; }
|
||||
uint32_t scope_id() const { return scope_id_; }
|
||||
@ -634,24 +612,25 @@ class CooperativeMatrixNV : public Type {
|
||||
const uint32_t columns_id_;
|
||||
};
|
||||
|
||||
#define DefineParameterlessType(type, name) \
|
||||
class type : public Type { \
|
||||
public: \
|
||||
type() : Type(k##type) {} \
|
||||
type(const type&) = default; \
|
||||
\
|
||||
std::string str() const override { return #name; } \
|
||||
\
|
||||
type* As##type() override { return this; } \
|
||||
const type* As##type() const override { return this; } \
|
||||
\
|
||||
void GetExtraHashWords(std::vector<uint32_t>*, \
|
||||
std::unordered_set<const Type*>*) const override {} \
|
||||
\
|
||||
private: \
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override { \
|
||||
return that->As##type() && HasSameDecorations(that); \
|
||||
} \
|
||||
#define DefineParameterlessType(type, name) \
|
||||
class type : public Type { \
|
||||
public: \
|
||||
type() : Type(k##type) {} \
|
||||
type(const type&) = default; \
|
||||
\
|
||||
std::string str() const override { return #name; } \
|
||||
\
|
||||
type* As##type() override { return this; } \
|
||||
const type* As##type() const override { return this; } \
|
||||
\
|
||||
size_t ComputeExtraStateHash(size_t hash, SeenTypes*) const override { \
|
||||
return hash; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
bool IsSameImpl(const Type* that, IsSameCache*) const override { \
|
||||
return that->As##type() && HasSameDecorations(that); \
|
||||
} \
|
||||
}
|
||||
DefineParameterlessType(Void, void);
|
||||
DefineParameterlessType(Bool, bool);
|
||||
|
53
source/util/hash_combine.h
Normal file
53
source/util/hash_combine.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2022 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SOURCE_UTIL_HASH_COMBINE_H_
|
||||
#define SOURCE_UTIL_HASH_COMBINE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace spvtools {
|
||||
namespace utils {
|
||||
|
||||
// Helpers for incrementally computing hashes.
|
||||
// For reference, see
|
||||
// http://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
|
||||
|
||||
template <typename T>
|
||||
inline size_t hash_combine(std::size_t seed, const T& val) {
|
||||
return seed ^ (std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t hash_combine(std::size_t hash, const std::vector<T>& vals) {
|
||||
for (const T& val : vals) {
|
||||
hash = hash_combine(hash, val);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
inline size_t hash_combine(std::size_t hash) { return hash; }
|
||||
|
||||
template <typename T, typename... Types>
|
||||
inline size_t hash_combine(std::size_t hash, const T& val,
|
||||
const Types&... args) {
|
||||
return hash_combine(hash_combine(hash, val), args...);
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_UTIL_HASH_COMBINE_H_
|
@ -333,6 +333,15 @@ class SmallVector {
|
||||
++size_;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
if (large_data_) {
|
||||
large_data_->pop_back();
|
||||
} else {
|
||||
--size_;
|
||||
small_data_[size_].~T();
|
||||
}
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
iterator insert(iterator pos, InputIt first, InputIt last) {
|
||||
size_t element_idx = (pos - begin());
|
||||
|
@ -16,6 +16,7 @@ add_spvtools_unittest(TARGET utils
|
||||
SRCS ilist_test.cpp
|
||||
bit_vector_test.cpp
|
||||
bitutils_test.cpp
|
||||
hash_combine_test.cpp
|
||||
small_vector_test.cpp
|
||||
LIBS SPIRV-Tools-opt
|
||||
)
|
||||
|
43
test/util/hash_combine_test.cpp
Normal file
43
test/util/hash_combine_test.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2022 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/util/hash_combine.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace utils {
|
||||
namespace {
|
||||
|
||||
using HashCombineTest = ::testing::Test;
|
||||
|
||||
TEST(HashCombineTest, Identity) { EXPECT_EQ(hash_combine(0), 0); }
|
||||
|
||||
TEST(HashCombineTest, Variadic) {
|
||||
// Expect manual and variadic template versions be the same.
|
||||
EXPECT_EQ(hash_combine(hash_combine(hash_combine(0, 1), 2), 3),
|
||||
hash_combine(0, 1, 2, 3));
|
||||
}
|
||||
|
||||
TEST(HashCombineTest, Vector) {
|
||||
// Expect variadic and vector versions be the same.
|
||||
EXPECT_EQ(hash_combine(0, std::vector<uint32_t>({1, 2, 3})),
|
||||
hash_combine(0, 1, 2, 3));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace utils
|
||||
} // namespace spvtools
|
@ -605,6 +605,68 @@ TEST(SmallVectorTest, Resize6) {
|
||||
EXPECT_EQ(vec, result);
|
||||
}
|
||||
|
||||
TEST(SmallVectorTest, Pop_back) {
|
||||
SmallVector<uint32_t, 8> vec = {0, 1, 2, 10, 10, 10};
|
||||
SmallVector<uint32_t, 8> result = {0, 1, 2};
|
||||
|
||||
EXPECT_EQ(vec.size(), 6);
|
||||
vec.pop_back();
|
||||
vec.pop_back();
|
||||
vec.pop_back();
|
||||
EXPECT_EQ(vec.size(), 3);
|
||||
EXPECT_EQ(vec, result);
|
||||
}
|
||||
|
||||
TEST(SmallVectorTest, Pop_back_TestDestructor) {
|
||||
// Tracks number of constructions and destructions to ensure they are called.
|
||||
struct TracksDtor {
|
||||
TracksDtor& operator=(TracksDtor&&) = delete;
|
||||
TracksDtor& operator=(const TracksDtor&) = delete;
|
||||
|
||||
TracksDtor(int& num_ctors, int& num_dtors)
|
||||
: num_ctors_(num_ctors), num_dtors_(num_dtors) {
|
||||
num_ctors_++;
|
||||
}
|
||||
TracksDtor(const TracksDtor& that)
|
||||
: TracksDtor(that.num_ctors_, that.num_dtors_) {}
|
||||
TracksDtor(TracksDtor&& that)
|
||||
: TracksDtor(that.num_ctors_, that.num_dtors_) {}
|
||||
~TracksDtor() { num_dtors_++; }
|
||||
|
||||
int& num_ctors_;
|
||||
int& num_dtors_;
|
||||
};
|
||||
|
||||
constexpr int capacity = 4;
|
||||
SmallVector<TracksDtor, capacity> vec;
|
||||
|
||||
int num_ctors = 0;
|
||||
int num_dtors = 0;
|
||||
|
||||
// Make sure it works when staying within the smallvector capacity
|
||||
for (int i = 0; i < capacity; ++i) {
|
||||
vec.emplace_back(num_ctors, num_dtors);
|
||||
}
|
||||
|
||||
EXPECT_EQ(num_ctors, capacity);
|
||||
while (!vec.empty()) {
|
||||
vec.pop_back();
|
||||
}
|
||||
|
||||
EXPECT_EQ(num_ctors, capacity);
|
||||
EXPECT_EQ(num_dtors, num_ctors);
|
||||
|
||||
// And when larger than builtin capacity
|
||||
for (int i = 0; i < capacity * 2; ++i) {
|
||||
vec.emplace_back(num_ctors, num_dtors);
|
||||
}
|
||||
|
||||
while (!vec.empty()) {
|
||||
vec.pop_back();
|
||||
}
|
||||
EXPECT_EQ(num_dtors, num_ctors);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace utils
|
||||
} // namespace spvtools
|
||||
|
Loading…
Reference in New Issue
Block a user