mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-18 21:13:02 +01:00
Updated spirv-tools.
This commit is contained in:
177
3rdparty/spirv-tools/source/diff/diff.cpp
vendored
177
3rdparty/spirv-tools/source/diff/diff.cpp
vendored
@@ -101,9 +101,12 @@ class IdMap {
|
||||
return from < id_map_.size() && id_map_[from] != 0;
|
||||
}
|
||||
|
||||
// Map any ids in src and dst that have not been mapped to new ids in dst and
|
||||
// src respectively.
|
||||
void MapUnmatchedIds(IdMap& other_way);
|
||||
bool IsMapped(const opt::Instruction* from_inst) const {
|
||||
assert(from_inst != nullptr);
|
||||
assert(!from_inst->HasResultId());
|
||||
|
||||
return inst_map_.find(from_inst) != inst_map_.end();
|
||||
}
|
||||
|
||||
// Some instructions don't have result ids. Those are mapped by pointer.
|
||||
void MapInsts(const opt::Instruction* from_inst,
|
||||
@@ -117,6 +120,12 @@ class IdMap {
|
||||
|
||||
uint32_t IdBound() const { return static_cast<uint32_t>(id_map_.size()); }
|
||||
|
||||
// Generate a fresh id in this mapping's domain.
|
||||
uint32_t MakeFreshId() {
|
||||
id_map_.push_back(0);
|
||||
return static_cast<uint32_t>(id_map_.size()) - 1;
|
||||
}
|
||||
|
||||
private:
|
||||
// Given an id, returns the corresponding id in the other module, or 0 if not
|
||||
// matched yet.
|
||||
@@ -150,10 +159,16 @@ class SrcDstIdMap {
|
||||
|
||||
bool IsSrcMapped(uint32_t src) { return src_to_dst_.IsMapped(src); }
|
||||
bool IsDstMapped(uint32_t dst) { return dst_to_src_.IsMapped(dst); }
|
||||
bool IsDstMapped(const opt::Instruction* dst_inst) {
|
||||
return dst_to_src_.IsMapped(dst_inst);
|
||||
}
|
||||
|
||||
// Map any ids in src and dst that have not been mapped to new ids in dst and
|
||||
// src respectively.
|
||||
void MapUnmatchedIds();
|
||||
// src respectively. Use src_insn_defined and dst_insn_defined to ignore ids
|
||||
// that are simply never defined. (Since we assume the inputs are valid
|
||||
// SPIR-V, this implies they are also never used.)
|
||||
void MapUnmatchedIds(std::function<bool(uint32_t)> src_insn_defined,
|
||||
std::function<bool(uint32_t)> dst_insn_defined);
|
||||
|
||||
// Some instructions don't have result ids. Those are mapped by pointer.
|
||||
void MapInsts(const opt::Instruction* src_inst,
|
||||
@@ -203,6 +218,11 @@ struct IdInstructions {
|
||||
|
||||
void MapIdToInstruction(uint32_t id, const opt::Instruction* inst);
|
||||
|
||||
// Return true if id is mapped to any instruction, false otherwise.
|
||||
bool IsDefined(uint32_t id) {
|
||||
return id < inst_map_.size() && inst_map_[id] != nullptr;
|
||||
}
|
||||
|
||||
void MapIdsToInstruction(
|
||||
opt::IteratorRange<opt::Module::const_inst_iterator> section);
|
||||
void MapIdsToInfos(
|
||||
@@ -338,6 +358,59 @@ class Differ {
|
||||
std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
|
||||
match_group);
|
||||
|
||||
// Bucket `src_ids` and `dst_ids` by the key ids returned by `get_group`, and
|
||||
// then call `match_group` on pairs of buckets whose key ids are matched with
|
||||
// each other.
|
||||
//
|
||||
// For example, suppose we want to pair up groups of instructions with the
|
||||
// same type. Naturally, the source instructions refer to their types by their
|
||||
// ids in the source, and the destination instructions use destination type
|
||||
// ids, so simply comparing source and destination type ids as integers, as
|
||||
// `GroupIdsAndMatch` would do, is meaningless. But if a prior call to
|
||||
// `MatchTypeIds` has established type matches between the two modules, then
|
||||
// we can consult those to pair source and destination buckets whose types are
|
||||
// equivalent.
|
||||
//
|
||||
// Suppose our input groups are as follows:
|
||||
//
|
||||
// - src_ids: { 1 -> 100, 2 -> 300, 3 -> 100, 4 -> 200 }
|
||||
// - dst_ids: { 5 -> 10, 6 -> 20, 7 -> 10, 8 -> 300 }
|
||||
//
|
||||
// Here, `X -> Y` means that the instruction with SPIR-V id `X` is a member of
|
||||
// the group, and `Y` is the id of its type. If we use
|
||||
// `Differ::GroupIdsHelperGetTypeId` for `get_group`, then
|
||||
// `get_group(X) == Y`.
|
||||
//
|
||||
// These instructions are bucketed by type as follows:
|
||||
//
|
||||
// - source: [1, 3] -> 100
|
||||
// [4] -> 200
|
||||
// [2] -> 300
|
||||
//
|
||||
// - destination: [5, 7] -> 10
|
||||
// [6] -> 20
|
||||
// [8] -> 300
|
||||
//
|
||||
// Now suppose that we have previously matched up src type 100 with dst type
|
||||
// 10, and src type 200 with dst type 20, but no other types are matched.
|
||||
//
|
||||
// Then `match_group` is called twice:
|
||||
// - Once with ([1,3], [5, 7]), corresponding to 100/10
|
||||
// - Once with ([4],[6]), corresponding to 200/20
|
||||
//
|
||||
// The source type 300 isn't matched with anything, so the fact that there's a
|
||||
// destination type 300 is irrelevant, and thus 2 and 8 are never passed to
|
||||
// `match_group`.
|
||||
//
|
||||
// This function isn't specific to types; it simply buckets by the ids
|
||||
// returned from `get_group`, and consults existing matches to pair up the
|
||||
// resulting buckets.
|
||||
void GroupIdsAndMatchByMappedId(
|
||||
const IdGroup& src_ids, const IdGroup& dst_ids,
|
||||
uint32_t (Differ::*get_group)(const IdInstructions&, uint32_t),
|
||||
std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
|
||||
match_group);
|
||||
|
||||
// Helper functions that determine if two instructions match
|
||||
bool DoIdsMatch(uint32_t src_id, uint32_t dst_id);
|
||||
bool DoesOperandMatch(const opt::Operand& src_operand,
|
||||
@@ -504,36 +577,27 @@ class Differ {
|
||||
FunctionMap dst_funcs_;
|
||||
};
|
||||
|
||||
void IdMap::MapUnmatchedIds(IdMap& other_way) {
|
||||
const uint32_t src_id_bound = static_cast<uint32_t>(id_map_.size());
|
||||
const uint32_t dst_id_bound = static_cast<uint32_t>(other_way.id_map_.size());
|
||||
|
||||
uint32_t next_src_id = src_id_bound;
|
||||
uint32_t next_dst_id = dst_id_bound;
|
||||
void SrcDstIdMap::MapUnmatchedIds(
|
||||
std::function<bool(uint32_t)> src_insn_defined,
|
||||
std::function<bool(uint32_t)> dst_insn_defined) {
|
||||
const uint32_t src_id_bound = static_cast<uint32_t>(src_to_dst_.IdBound());
|
||||
const uint32_t dst_id_bound = static_cast<uint32_t>(dst_to_src_.IdBound());
|
||||
|
||||
for (uint32_t src_id = 1; src_id < src_id_bound; ++src_id) {
|
||||
if (!IsMapped(src_id)) {
|
||||
MapIds(src_id, next_dst_id);
|
||||
|
||||
other_way.id_map_.push_back(0);
|
||||
other_way.MapIds(next_dst_id++, src_id);
|
||||
if (!src_to_dst_.IsMapped(src_id) && src_insn_defined(src_id)) {
|
||||
uint32_t fresh_dst_id = dst_to_src_.MakeFreshId();
|
||||
MapIds(src_id, fresh_dst_id);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t dst_id = 1; dst_id < dst_id_bound; ++dst_id) {
|
||||
if (!other_way.IsMapped(dst_id)) {
|
||||
id_map_.push_back(0);
|
||||
MapIds(next_src_id, dst_id);
|
||||
|
||||
other_way.MapIds(dst_id, next_src_id++);
|
||||
if (!dst_to_src_.IsMapped(dst_id) && dst_insn_defined(dst_id)) {
|
||||
uint32_t fresh_src_id = src_to_dst_.MakeFreshId();
|
||||
MapIds(fresh_src_id, dst_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SrcDstIdMap::MapUnmatchedIds() {
|
||||
src_to_dst_.MapUnmatchedIds(dst_to_src_);
|
||||
}
|
||||
|
||||
void IdInstructions::MapIdToInstruction(uint32_t id,
|
||||
const opt::Instruction* inst) {
|
||||
assert(id != 0);
|
||||
@@ -889,6 +953,37 @@ void Differ::GroupIdsAndMatch(
|
||||
}
|
||||
}
|
||||
|
||||
void Differ::GroupIdsAndMatchByMappedId(
|
||||
const IdGroup& src_ids, const IdGroup& dst_ids,
|
||||
uint32_t (Differ::*get_group)(const IdInstructions&, uint32_t),
|
||||
std::function<void(const IdGroup& src_group, const IdGroup& dst_group)>
|
||||
match_group) {
|
||||
// Group the ids based on a key (get_group)
|
||||
std::map<uint32_t, IdGroup> src_groups;
|
||||
std::map<uint32_t, IdGroup> dst_groups;
|
||||
|
||||
GroupIds<uint32_t>(src_ids, true, &src_groups, get_group);
|
||||
GroupIds<uint32_t>(dst_ids, false, &dst_groups, get_group);
|
||||
|
||||
// Iterate over pairs of groups whose keys map to each other.
|
||||
for (const auto& iter : src_groups) {
|
||||
const uint32_t& src_key = iter.first;
|
||||
const IdGroup& src_group = iter.second;
|
||||
|
||||
if (src_key == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (id_map_.IsSrcMapped(src_key)) {
|
||||
const uint32_t& dst_key = id_map_.MappedDstId(src_key);
|
||||
const IdGroup& dst_group = dst_groups[dst_key];
|
||||
|
||||
// Let the caller match the groups as appropriate.
|
||||
match_group(src_group, dst_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Differ::DoIdsMatch(uint32_t src_id, uint32_t dst_id) {
|
||||
assert(dst_id != 0);
|
||||
return id_map_.MappedDstId(src_id) == dst_id;
|
||||
@@ -1419,7 +1514,6 @@ void Differ::MatchTypeForwardPointersByName(const IdGroup& src,
|
||||
GroupIdsAndMatch<std::string>(
|
||||
src, dst, "", &Differ::GetSanitizedName,
|
||||
[this](const IdGroup& src_group, const IdGroup& dst_group) {
|
||||
|
||||
// Match only if there's a unique forward declaration with this debug
|
||||
// name.
|
||||
if (src_group.size() == 1 && dst_group.size() == 1) {
|
||||
@@ -1574,6 +1668,8 @@ void Differ::BestEffortMatchFunctions(const IdGroup& src_func_ids,
|
||||
|
||||
id_map_.MapIds(match_result.src_id, match_result.dst_id);
|
||||
|
||||
MatchFunctionParamIds(src_funcs_[match_result.src_id],
|
||||
dst_funcs_[match_result.dst_id]);
|
||||
MatchIdsInFunctionBodies(src_func_insts.at(match_result.src_id),
|
||||
dst_func_insts.at(match_result.dst_id),
|
||||
match_result.src_match, match_result.dst_match, 0);
|
||||
@@ -1598,7 +1694,6 @@ void Differ::MatchFunctionParamIds(const opt::Function* src_func,
|
||||
GroupIdsAndMatch<std::string>(
|
||||
src_params, dst_params, "", &Differ::GetSanitizedName,
|
||||
[this](const IdGroup& src_group, const IdGroup& dst_group) {
|
||||
|
||||
// There shouldn't be two parameters with the same name, so the ids
|
||||
// should match. There is nothing restricting the SPIR-V however to have
|
||||
// two parameters with the same name, so be resilient against that.
|
||||
@@ -1609,17 +1704,17 @@ void Differ::MatchFunctionParamIds(const opt::Function* src_func,
|
||||
|
||||
// Then match the parameters by their type. If there are multiple of them,
|
||||
// match them by their order.
|
||||
GroupIdsAndMatch<uint32_t>(
|
||||
src_params, dst_params, 0, &Differ::GroupIdsHelperGetTypeId,
|
||||
GroupIdsAndMatchByMappedId(
|
||||
src_params, dst_params, &Differ::GroupIdsHelperGetTypeId,
|
||||
[this](const IdGroup& src_group_by_type_id,
|
||||
const IdGroup& dst_group_by_type_id) {
|
||||
|
||||
const size_t shared_param_count =
|
||||
std::min(src_group_by_type_id.size(), dst_group_by_type_id.size());
|
||||
|
||||
for (size_t param_index = 0; param_index < shared_param_count;
|
||||
++param_index) {
|
||||
id_map_.MapIds(src_group_by_type_id[0], dst_group_by_type_id[0]);
|
||||
id_map_.MapIds(src_group_by_type_id[param_index],
|
||||
dst_group_by_type_id[param_index]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2064,9 +2159,10 @@ void Differ::MatchEntryPointIds() {
|
||||
}
|
||||
|
||||
// Otherwise match them by name.
|
||||
bool matched = false;
|
||||
for (const opt::Instruction* src_inst : src_insts) {
|
||||
for (const opt::Instruction* dst_inst : dst_insts) {
|
||||
if (id_map_.IsDstMapped(dst_inst)) continue;
|
||||
|
||||
const opt::Operand& src_name = src_inst->GetOperand(2);
|
||||
const opt::Operand& dst_name = dst_inst->GetOperand(2);
|
||||
|
||||
@@ -2075,13 +2171,9 @@ void Differ::MatchEntryPointIds() {
|
||||
uint32_t dst_id = dst_inst->GetSingleWordOperand(1);
|
||||
id_map_.MapIds(src_id, dst_id);
|
||||
id_map_.MapInsts(src_inst, dst_inst);
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2126,7 +2218,6 @@ void Differ::MatchTypeForwardPointers() {
|
||||
spv::StorageClass::Max, &Differ::GroupIdsHelperGetTypePointerStorageClass,
|
||||
[this](const IdGroup& src_group_by_storage_class,
|
||||
const IdGroup& dst_group_by_storage_class) {
|
||||
|
||||
// Group them further by the type they are pointing to and loop over
|
||||
// them.
|
||||
GroupIdsAndMatch<spv::Op>(
|
||||
@@ -2134,7 +2225,6 @@ void Differ::MatchTypeForwardPointers() {
|
||||
spv::Op::Max, &Differ::GroupIdsHelperGetTypePointerTypeOp,
|
||||
[this](const IdGroup& src_group_by_type_op,
|
||||
const IdGroup& dst_group_by_type_op) {
|
||||
|
||||
// Group them even further by debug info, if possible and match by
|
||||
// debug name.
|
||||
MatchTypeForwardPointersByName(src_group_by_type_op,
|
||||
@@ -2199,7 +2289,9 @@ void Differ::MatchTypeIds() {
|
||||
case spv::Op::OpTypeVoid:
|
||||
case spv::Op::OpTypeBool:
|
||||
case spv::Op::OpTypeSampler:
|
||||
// void, bool and sampler are unique, match them.
|
||||
case spv::Op::OpTypeAccelerationStructureNV:
|
||||
case spv::Op::OpTypeRayQueryKHR:
|
||||
// the above types have no operands and are unique, match them.
|
||||
return true;
|
||||
case spv::Op::OpTypeInt:
|
||||
case spv::Op::OpTypeFloat:
|
||||
@@ -2378,7 +2470,6 @@ void Differ::MatchFunctions() {
|
||||
GroupIdsAndMatch<std::string>(
|
||||
src_func_ids, dst_func_ids, "", &Differ::GetSanitizedName,
|
||||
[this](const IdGroup& src_group, const IdGroup& dst_group) {
|
||||
|
||||
// If there is a single function with this name in src and dst, it's a
|
||||
// definite match.
|
||||
if (src_group.size() == 1 && dst_group.size() == 1) {
|
||||
@@ -2392,7 +2483,6 @@ void Differ::MatchFunctions() {
|
||||
&Differ::GroupIdsHelperGetTypeId,
|
||||
[this](const IdGroup& src_group_by_type_id,
|
||||
const IdGroup& dst_group_by_type_id) {
|
||||
|
||||
if (src_group_by_type_id.size() == 1 &&
|
||||
dst_group_by_type_id.size() == 1) {
|
||||
id_map_.MapIds(src_group_by_type_id[0],
|
||||
@@ -2437,7 +2527,6 @@ void Differ::MatchFunctions() {
|
||||
src_func_ids, dst_func_ids, 0, &Differ::GroupIdsHelperGetTypeId,
|
||||
[this](const IdGroup& src_group_by_type_id,
|
||||
const IdGroup& dst_group_by_type_id) {
|
||||
|
||||
BestEffortMatchFunctions(src_group_by_type_id, dst_group_by_type_id,
|
||||
src_func_insts_, dst_func_insts_);
|
||||
});
|
||||
@@ -2647,7 +2736,9 @@ opt::Instruction Differ::ToMappedSrcIds(const opt::Instruction& dst_inst) {
|
||||
}
|
||||
|
||||
spv_result_t Differ::Output() {
|
||||
id_map_.MapUnmatchedIds();
|
||||
id_map_.MapUnmatchedIds(
|
||||
[this](uint32_t src_id) { return src_id_to_.IsDefined(src_id); },
|
||||
[this](uint32_t dst_id) { return dst_id_to_.IsDefined(dst_id); });
|
||||
src_id_to_.inst_map_.resize(id_map_.SrcToDstMap().IdBound(), nullptr);
|
||||
dst_id_to_.inst_map_.resize(id_map_.DstToSrcMap().IdBound(), nullptr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user