mirror of
https://github.com/yuzu-emu/sirit
synced 2024-11-22 08:03:38 +00:00
operand: Implement operand hashing and use hashed set for declarations
Instead of manually searching each element in the declarations vector, use an unordered_set to emplace new declarations avoiding repetition.
This commit is contained in:
parent
f7c4b07a7e
commit
1e665afa36
10 changed files with 66 additions and 13 deletions
|
@ -933,7 +933,8 @@ private:
|
||||||
std::vector<std::unique_ptr<Op>> execution_modes;
|
std::vector<std::unique_ptr<Op>> execution_modes;
|
||||||
std::vector<std::unique_ptr<Op>> debug;
|
std::vector<std::unique_ptr<Op>> debug;
|
||||||
std::vector<std::unique_ptr<Op>> annotations;
|
std::vector<std::unique_ptr<Op>> annotations;
|
||||||
std::vector<std::unique_ptr<Op>> declarations;
|
std::unordered_set<std::unique_ptr<Op>> declarations;
|
||||||
|
std::vector<Id> sorted_declarations;
|
||||||
|
|
||||||
std::vector<Id> global_variables;
|
std::vector<Id> global_variables;
|
||||||
|
|
||||||
|
|
|
@ -35,4 +35,8 @@ bool LiteralNumber::operator==(const Operand& other) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t LiteralNumber::Hash() const {
|
||||||
|
return static_cast<std::size_t>(raw) ^ Operand::Hash();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Sirit
|
} // namespace Sirit
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include "operand.h"
|
#include "operand.h"
|
||||||
|
@ -23,6 +24,8 @@ public:
|
||||||
|
|
||||||
bool operator==(const Operand& other) const override;
|
bool operator==(const Operand& other) const override;
|
||||||
|
|
||||||
|
std::size_t Hash() const override;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static LiteralNumber* Create(T value) {
|
static LiteralNumber* Create(T value) {
|
||||||
static_assert(sizeof(T) == 4 || sizeof(T) == 8);
|
static_assert(sizeof(T) == 4 || sizeof(T) == 8);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* Lesser General Public License version 3 or any later version.
|
* Lesser General Public License version 3 or any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common_types.h"
|
#include "common_types.h"
|
||||||
#include "literal_string.h"
|
#include "literal_string.h"
|
||||||
|
@ -36,4 +37,8 @@ bool LiteralString::operator==(const Operand& other) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t LiteralString::Hash() const {
|
||||||
|
return Operand::Hash() ^ std::hash<std::string>{}(string);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Sirit
|
} // namespace Sirit
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "operand.h"
|
#include "operand.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
@ -22,8 +23,10 @@ public:
|
||||||
|
|
||||||
bool operator==(const Operand& other) const override;
|
bool operator==(const Operand& other) const override;
|
||||||
|
|
||||||
|
std::size_t Hash() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string string;
|
std::string string;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Sirit
|
} // namespace Sirit
|
||||||
|
|
16
src/op.cpp
16
src/op.cpp
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
#include "common_types.h"
|
#include "common_types.h"
|
||||||
#include "literal_number.h"
|
#include "literal_number.h"
|
||||||
|
@ -47,6 +48,21 @@ bool Op::operator==(const Operand& other) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t Op::Hash() const {
|
||||||
|
std::size_t hash = Operand::Hash();
|
||||||
|
hash ^= static_cast<std::size_t>(opcode) << 20;
|
||||||
|
if (result_type) {
|
||||||
|
hash ^= result_type->Hash() << 16;
|
||||||
|
}
|
||||||
|
hash ^= static_cast<std::size_t>(id.value_or(0)) << 8;
|
||||||
|
std::size_t wrap = 32;
|
||||||
|
for (const auto operand : operands) {
|
||||||
|
wrap = (wrap + 7) % (sizeof(std::size_t) * CHAR_BIT);
|
||||||
|
hash ^= operand->Hash() << wrap;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
void Op::Write(Stream& stream) const {
|
void Op::Write(Stream& stream) const {
|
||||||
stream.Write(static_cast<u16>(opcode));
|
stream.Write(static_cast<u16>(opcode));
|
||||||
stream.Write(WordCount());
|
stream.Write(WordCount());
|
||||||
|
|
3
src/op.h
3
src/op.h
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "common_types.h"
|
#include "common_types.h"
|
||||||
#include "operand.h"
|
#include "operand.h"
|
||||||
|
@ -24,6 +25,8 @@ public:
|
||||||
|
|
||||||
bool operator==(const Operand& other) const override;
|
bool operator==(const Operand& other) const override;
|
||||||
|
|
||||||
|
std::size_t Hash() const override;
|
||||||
|
|
||||||
void Write(Stream& stream) const;
|
void Write(Stream& stream) const;
|
||||||
|
|
||||||
void Sink(Operand* operand);
|
void Sink(Operand* operand);
|
||||||
|
|
|
@ -30,6 +30,10 @@ bool Operand::operator!=(const Operand& other) const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t Operand::Hash() const {
|
||||||
|
return static_cast<std::size_t>(operand_type) << 30;
|
||||||
|
}
|
||||||
|
|
||||||
OperandType Operand::GetType() const {
|
OperandType Operand::GetType() const {
|
||||||
return operand_type;
|
return operand_type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include "common_types.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
namespace Sirit {
|
namespace Sirit {
|
||||||
|
@ -23,6 +25,8 @@ public:
|
||||||
virtual bool operator==(const Operand& other) const;
|
virtual bool operator==(const Operand& other) const;
|
||||||
bool operator!=(const Operand& other) const;
|
bool operator!=(const Operand& other) const;
|
||||||
|
|
||||||
|
virtual std::size_t Hash() const;
|
||||||
|
|
||||||
OperandType GetType() const;
|
OperandType GetType() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -30,3 +34,14 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Sirit
|
} // namespace Sirit
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<Sirit::Operand> {
|
||||||
|
std::size_t operator()(const Sirit::Operand& operand) const noexcept {
|
||||||
|
return operand.Hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
|
@ -59,7 +59,7 @@ std::vector<u8> Module::Assemble() const {
|
||||||
WriteSet(stream, execution_modes);
|
WriteSet(stream, execution_modes);
|
||||||
WriteSet(stream, debug);
|
WriteSet(stream, debug);
|
||||||
WriteSet(stream, annotations);
|
WriteSet(stream, annotations);
|
||||||
WriteSet(stream, declarations);
|
WriteSet(stream, sorted_declarations);
|
||||||
WriteSet(stream, global_variables);
|
WriteSet(stream, global_variables);
|
||||||
WriteSet(stream, code);
|
WriteSet(stream, code);
|
||||||
|
|
||||||
|
@ -74,13 +74,14 @@ void Module::AddCapability(spv::Capability capability) {
|
||||||
capabilities.insert(capability);
|
capabilities.insert(capability);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::SetMemoryModel(spv::AddressingModel addressing_model_, spv::MemoryModel memory_model_) {
|
void Module::SetMemoryModel(spv::AddressingModel addressing_model_,
|
||||||
|
spv::MemoryModel memory_model_) {
|
||||||
this->addressing_model = addressing_model_;
|
this->addressing_model = addressing_model_;
|
||||||
this->memory_model = memory_model_;
|
this->memory_model = memory_model_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point,
|
void Module::AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string name,
|
||||||
std::string name, const std::vector<Id>& interfaces) {
|
const std::vector<Id>& interfaces) {
|
||||||
auto op{std::make_unique<Op>(spv::Op::OpEntryPoint)};
|
auto op{std::make_unique<Op>(spv::Op::OpEntryPoint)};
|
||||||
op->Add(static_cast<u32>(execution_model));
|
op->Add(static_cast<u32>(execution_model));
|
||||||
op->Add(entry_point);
|
op->Add(entry_point);
|
||||||
|
@ -121,14 +122,12 @@ Id Module::AddCode(spv::Op opcode, std::optional<u32> id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Id Module::AddDeclaration(std::unique_ptr<Op> op) {
|
Id Module::AddDeclaration(std::unique_ptr<Op> op) {
|
||||||
const auto& found{std::find_if(declarations.begin(), declarations.end(),
|
const auto [it, is_inserted] = declarations.emplace(std::move(op));
|
||||||
[&op](const auto& other) { return *other == *op; })};
|
const Id id = it->get();
|
||||||
if (found != declarations.end()) {
|
if (is_inserted) {
|
||||||
return found->get();
|
sorted_declarations.push_back(id);
|
||||||
|
++bound;
|
||||||
}
|
}
|
||||||
const auto id = op.get();
|
|
||||||
declarations.push_back(std::move(op));
|
|
||||||
bound++;
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue