SPIRV-Tools/source/opt/def_use_manager.cpp

372 lines
12 KiB
C++
Raw Normal View History

2016-07-27 21:37:04 +00:00
// Copyright (c) 2016 Google 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
2016-07-27 21:37:04 +00:00
//
// http://www.apache.org/licenses/LICENSE-2.0
2016-07-27 21:37:04 +00:00
//
// 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.
2016-07-27 21:37:04 +00:00
#include "source/opt/def_use_manager.h"
#include "source/util/make_unique.h"
2016-07-27 21:37:04 +00:00
namespace spvtools {
namespace opt {
namespace analysis {
// Don't compact before we have a reasonable number of ids allocated (~32kb).
static const size_t kCompactThresholdMinTotalIds = (8 * 1024);
// Compact when fewer than this fraction of the storage is used (should be 2^n
// for performance).
static const size_t kCompactThresholdFractionFreeIds = 8;
DefUseManager::DefUseManager() {
use_pool_ = MakeUnique<UseListPool>();
used_id_pool_ = MakeUnique<UsedIdListPool>();
}
void DefUseManager::AnalyzeInstDef(Instruction* inst) {
const uint32_t def_id = inst->result_id();
if (def_id != 0) {
auto iter = id_to_def_.find(def_id);
if (iter != id_to_def_.end()) {
// Clear the original instruction that defining the same result id of the
// new instruction.
ClearInst(iter->second);
}
id_to_def_[def_id] = inst;
} else {
ClearInst(inst);
}
}
void DefUseManager::AnalyzeInstUse(Instruction* inst) {
// It might have existed before.
EraseUseRecordsOfOperandIds(inst);
// Create entry for the given instruction. Note that the instruction may
// not have any in-operands. In such cases, we still need a entry for those
// instructions so this manager knows it has seen the instruction later.
UsedIdList& used_ids =
inst_to_used_id_.insert({inst, UsedIdList(used_id_pool_.get())})
.first->second;
for (uint32_t i = 0; i < inst->NumOperands(); ++i) {
switch (inst->GetOperand(i).type) {
// For any id type but result id type
case SPV_OPERAND_TYPE_ID:
case SPV_OPERAND_TYPE_TYPE_ID:
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
case SPV_OPERAND_TYPE_SCOPE_ID: {
uint32_t use_id = inst->GetSingleWordOperand(i);
Instruction* def = GetDef(use_id);
assert(def && "Definition is not registered.");
// Add to inst's use records
used_ids.push_back(use_id);
// Add to the users, taking care to avoid adding duplicates. We know
// the duplicate for this instruction will always be at the tail.
UseList& list = inst_to_users_.insert({def, UseList(use_pool_.get())})
.first->second;
if (list.empty() || list.back() != inst) {
list.push_back(inst);
}
} break;
default:
break;
}
}
}
void DefUseManager::AnalyzeInstDefUse(Instruction* inst) {
AnalyzeInstDef(inst);
AnalyzeInstUse(inst);
// Analyze lines last otherwise they will be cleared when inst is
// cleared by preceding two calls
for (auto& l_inst : inst->dbg_line_insts()) AnalyzeInstDefUse(&l_inst);
}
void DefUseManager::UpdateDefUse(Instruction* inst) {
const uint32_t def_id = inst->result_id();
if (def_id != 0) {
auto iter = id_to_def_.find(def_id);
if (iter == id_to_def_.end()) {
AnalyzeInstDef(inst);
}
}
AnalyzeInstUse(inst);
}
Instruction* DefUseManager::GetDef(uint32_t id) {
auto iter = id_to_def_.find(id);
if (iter == id_to_def_.end()) return nullptr;
return iter->second;
2016-07-27 21:37:04 +00:00
}
const Instruction* DefUseManager::GetDef(uint32_t id) const {
const auto iter = id_to_def_.find(id);
if (iter == id_to_def_.end()) return nullptr;
return iter->second;
}
bool DefUseManager::WhileEachUser(
const Instruction* def, const std::function<bool(Instruction*)>& f) const {
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
// Ensure that |def| has been registered.
assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) &&
"Definition is not registered.");
if (!def->HasResultId()) return true;
auto iter = inst_to_users_.find(def);
if (iter != inst_to_users_.end()) {
for (Instruction* user : iter->second) {
if (!f(user)) return false;
}
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
}
return true;
}
bool DefUseManager::WhileEachUser(
uint32_t id, const std::function<bool(Instruction*)>& f) const {
return WhileEachUser(GetDef(id), f);
}
void DefUseManager::ForEachUser(
const Instruction* def, const std::function<void(Instruction*)>& f) const {
WhileEachUser(def, [&f](Instruction* user) {
f(user);
return true;
});
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
}
void DefUseManager::ForEachUser(
uint32_t id, const std::function<void(Instruction*)>& f) const {
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
ForEachUser(GetDef(id), f);
}
bool DefUseManager::WhileEachUse(
const Instruction* def,
const std::function<bool(Instruction*, uint32_t)>& f) const {
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
// Ensure that |def| has been registered.
assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) &&
"Definition is not registered.");
if (!def->HasResultId()) return true;
auto iter = inst_to_users_.find(def);
if (iter != inst_to_users_.end()) {
for (Instruction* user : iter->second) {
for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) {
const Operand& op = user->GetOperand(idx);
if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) {
if (def->result_id() == op.words[0]) {
if (!f(user, idx)) return false;
}
}
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
}
}
}
return true;
}
bool DefUseManager::WhileEachUse(
uint32_t id, const std::function<bool(Instruction*, uint32_t)>& f) const {
return WhileEachUse(GetDef(id), f);
}
void DefUseManager::ForEachUse(
const Instruction* def,
const std::function<void(Instruction*, uint32_t)>& f) const {
WhileEachUse(def, [&f](Instruction* user, uint32_t index) {
f(user, index);
return true;
});
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
}
void DefUseManager::ForEachUse(
uint32_t id, const std::function<void(Instruction*, uint32_t)>& f) const {
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
ForEachUse(GetDef(id), f);
}
uint32_t DefUseManager::NumUsers(const Instruction* def) const {
uint32_t count = 0;
ForEachUser(def, [&count](Instruction*) { ++count; });
return count;
}
uint32_t DefUseManager::NumUsers(uint32_t id) const {
return NumUsers(GetDef(id));
}
uint32_t DefUseManager::NumUses(const Instruction* def) const {
uint32_t count = 0;
ForEachUse(def, [&count](Instruction*, uint32_t) { ++count; });
return count;
}
uint32_t DefUseManager::NumUses(uint32_t id) const {
return NumUses(GetDef(id));
}
std::vector<Instruction*> DefUseManager::GetAnnotations(uint32_t id) const {
std::vector<Instruction*> annos;
const Instruction* def = GetDef(id);
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
if (!def) return annos;
ForEachUser(def, [&annos](Instruction* user) {
if (IsAnnotationInst(user->opcode())) {
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
annos.push_back(user);
}
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
});
return annos;
}
void DefUseManager::AnalyzeDefUse(Module* module) {
if (!module) return;
Adding new def -> use mapping container Replaced representation of uses * Changed uses from unordered_map<uint32_t, UseList> to set<pairInstruction*, Instruction*>> * Replaced GetUses with ForEachUser and ForEachUse functions * updated passes to use new functions * partially updated tests * lots of cleanup still todo Adding an unique id to Instruction generated by IRContext Each instruction is given an unique id that can be used for ordering purposes. The ids are generated via the IRContext. Major changes: * Instructions now contain a uint32_t for unique id and a cached context pointer * Most constructors have been modified to take a context as input * unfortunately I cannot remove the default and copy constructors, but developers should avoid these * Added accessors to parents of basic block and function * Removed the copy constructors for BasicBlock and Function and replaced them with Clone functions * Reworked BuildModule to return an IRContext owning the built module * Since all instructions require a context, the context now becomes the basic unit for IR * Added a constructor to context to create an owned module internally * Replaced uses of Instruction's copy constructor with Clone whereever I found them * Reworked the linker functionality to perform clones into a different context instead of moves * Updated many tests to be consistent with the above changes * Still need to add new tests to cover added functionality * Added comparison operators to Instruction Adding tests for Instruction, IRContext and IR loading Fixed some header comments for BuildModule Fixes to get tests passing again * Reordered two linker steps to avoid use/def problems * Fixed def/use manager uses in merge return pass * Added early return for GetAnnotations * Changed uses of Instruction::ToNop in passes to IRContext::KillInst Simplifying the uses for some contexts in passes
2017-11-14 19:11:50 +00:00
// Analyze all the defs before any uses to catch forward references.
module->ForEachInst(
std::bind(&DefUseManager::AnalyzeInstDef, this, std::placeholders::_1),
true);
module->ForEachInst(
std::bind(&DefUseManager::AnalyzeInstUse, this, std::placeholders::_1),
true);
}
void DefUseManager::ClearInst(Instruction* inst) {
if (inst_to_used_id_.find(inst) != inst_to_used_id_.end()) {
EraseUseRecordsOfOperandIds(inst);
uint32_t const result_id = inst->result_id();
if (result_id != 0) {
// For each using instruction, remove result_id from their used ids.
auto iter = inst_to_users_.find(inst);
if (iter != inst_to_users_.end()) {
for (Instruction* use : iter->second) {
inst_to_used_id_.at(use).remove_first(result_id);
}
inst_to_users_.erase(iter);
}
id_to_def_.erase(inst->result_id());
}
}
}
void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) {
// Go through all ids used by this instruction, remove this instruction's
// uses of them.
auto iter = inst_to_used_id_.find(inst);
if (iter != inst_to_used_id_.end()) {
const UsedIdList& used_ids = iter->second;
for (uint32_t def_id : used_ids) {
auto def_iter = inst_to_users_.find(GetDef(def_id));
if (def_iter != inst_to_users_.end()) {
def_iter->second.remove_first(const_cast<Instruction*>(inst));
}
}
inst_to_used_id_.erase(inst);
// If we're using only a fraction of the space in used_ids_, compact storage
// to prevent memory usage from being unbounded.
if (used_id_pool_->total_nodes() > kCompactThresholdMinTotalIds &&
used_id_pool_->used_nodes() <
used_id_pool_->total_nodes() / kCompactThresholdFractionFreeIds) {
CompactStorage();
}
}
}
void DefUseManager::CompactStorage() {
CompactUseRecords();
CompactUsedIds();
}
void DefUseManager::CompactUseRecords() {
std::unique_ptr<UseListPool> new_pool = MakeUnique<UseListPool>();
for (auto& iter : inst_to_users_) {
iter.second.move_nodes(new_pool.get());
}
use_pool_ = std::move(new_pool);
}
void DefUseManager::CompactUsedIds() {
std::unique_ptr<UsedIdListPool> new_pool = MakeUnique<UsedIdListPool>();
for (auto& iter : inst_to_used_id_) {
iter.second.move_nodes(new_pool.get());
}
used_id_pool_ = std::move(new_pool);
}
bool CompareAndPrintDifferences(const DefUseManager& lhs,
const DefUseManager& rhs) {
bool same = true;
if (lhs.id_to_def_ != rhs.id_to_def_) {
for (auto p : lhs.id_to_def_) {
if (rhs.id_to_def_.find(p.first) == rhs.id_to_def_.end()) {
printf("Diff in id_to_def: missing value in rhs\n");
}
}
for (auto p : rhs.id_to_def_) {
if (lhs.id_to_def_.find(p.first) == lhs.id_to_def_.end()) {
printf("Diff in id_to_def: missing value in lhs\n");
}
}
same = false;
}
for (const auto& l : lhs.inst_to_used_id_) {
std::set<uint32_t> ul, ur;
lhs.ForEachUse(l.first,
[&ul](Instruction*, uint32_t id) { ul.insert(id); });
rhs.ForEachUse(l.first,
[&ur](Instruction*, uint32_t id) { ur.insert(id); });
if (ul.size() != ur.size()) {
printf(
"Diff in inst_to_used_id_: different number of used ids (%zu != %zu)",
ul.size(), ur.size());
same = false;
} else if (ul != ur) {
printf("Diff in inst_to_used_id_: different used ids\n");
same = false;
}
}
for (const auto& r : rhs.inst_to_used_id_) {
auto iter_l = lhs.inst_to_used_id_.find(r.first);
if (r.second.empty() &&
!(iter_l == lhs.inst_to_used_id_.end() || iter_l->second.empty())) {
printf("Diff in inst_to_used_id_: unexpected instr in rhs\n");
same = false;
}
}
for (const auto& l : lhs.inst_to_users_) {
std::set<Instruction*> ul, ur;
lhs.ForEachUser(l.first, [&ul](Instruction* use) { ul.insert(use); });
rhs.ForEachUser(l.first, [&ur](Instruction* use) { ur.insert(use); });
if (ul.size() != ur.size()) {
printf("Diff in inst_to_users_: different number of users (%zu != %zu)",
ul.size(), ur.size());
same = false;
} else if (ul != ur) {
printf("Diff in inst_to_users_: different users\n");
same = false;
}
}
for (const auto& r : rhs.inst_to_users_) {
auto iter_l = lhs.inst_to_users_.find(r.first);
if (r.second.empty() &&
!(iter_l == lhs.inst_to_users_.end() || iter_l->second.empty())) {
printf("Diff in inst_to_users_: unexpected instr in rhs\n");
same = false;
}
}
return same;
}
2016-07-27 21:37:04 +00:00
} // namespace analysis
} // namespace opt
} // namespace spvtools