2016-07-27 21:37:04 +00:00
|
|
|
// Copyright (c) 2016 Google Inc.
|
|
|
|
//
|
2016-09-01 19:33:59 +00:00
|
|
|
// 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
|
|
|
//
|
2016-09-01 19:33:59 +00:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2016-07-27 21:37:04 +00:00
|
|
|
//
|
2016-09-01 19:33:59 +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 "def_use_manager.h"
|
|
|
|
|
2016-08-20 03:17:44 +00:00
|
|
|
#include "log.h"
|
2016-08-29 22:05:24 +00:00
|
|
|
#include "reflect.h"
|
2016-07-27 21:37:04 +00:00
|
|
|
|
|
|
|
namespace spvtools {
|
|
|
|
namespace opt {
|
|
|
|
namespace analysis {
|
|
|
|
|
2017-06-16 21:37:31 +00:00
|
|
|
void DefUseManager::AnalyzeInstDef(ir::Instruction* inst) {
|
2016-08-12 14:05:58 +00:00
|
|
|
const uint32_t def_id = inst->result_id();
|
2016-08-16 17:06:03 +00:00
|
|
|
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;
|
2017-11-08 17:40:02 +00:00
|
|
|
} else {
|
2016-08-16 17:06:03 +00:00
|
|
|
ClearInst(inst);
|
|
|
|
}
|
2017-06-16 21:37:31 +00:00
|
|
|
}
|
2016-08-12 14:43:26 +00:00
|
|
|
|
2017-06-16 21:37:31 +00:00
|
|
|
void DefUseManager::AnalyzeInstUse(ir::Instruction* inst) {
|
2016-08-16 17:06:03 +00:00
|
|
|
// 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.
|
|
|
|
inst_to_used_ids_[inst] = {};
|
2016-08-12 14:05:58 +00:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < inst->NumOperands(); ++i) {
|
|
|
|
switch (inst->GetOperand(i).type) {
|
|
|
|
// For any id type but result id type
|
2017-11-08 17:40:02 +00:00
|
|
|
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);
|
|
|
|
id_to_uses_[use_id].push_back({inst, i});
|
|
|
|
inst_to_used_ids_[inst].push_back(use_id);
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
break;
|
2016-08-12 14:05:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-16 21:37:31 +00:00
|
|
|
void DefUseManager::AnalyzeInstDefUse(ir::Instruction* inst) {
|
|
|
|
AnalyzeInstDef(inst);
|
|
|
|
AnalyzeInstUse(inst);
|
|
|
|
}
|
|
|
|
|
2016-07-27 21:37:04 +00:00
|
|
|
ir::Instruction* DefUseManager::GetDef(uint32_t id) {
|
2016-08-16 17:06:03 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-07-13 00:16:51 +00:00
|
|
|
const ir::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;
|
|
|
|
}
|
|
|
|
|
2016-07-27 21:37:04 +00:00
|
|
|
UseList* DefUseManager::GetUses(uint32_t id) {
|
2016-08-16 17:06:03 +00:00
|
|
|
auto iter = id_to_uses_.find(id);
|
|
|
|
if (iter == id_to_uses_.end()) return nullptr;
|
|
|
|
return &iter->second;
|
2016-07-27 21:37:04 +00:00
|
|
|
}
|
|
|
|
|
2016-08-29 22:05:24 +00:00
|
|
|
const UseList* DefUseManager::GetUses(uint32_t id) const {
|
|
|
|
const auto iter = id_to_uses_.find(id);
|
|
|
|
if (iter == id_to_uses_.end()) return nullptr;
|
|
|
|
return &iter->second;
|
|
|
|
}
|
|
|
|
|
2016-08-20 03:17:44 +00:00
|
|
|
std::vector<ir::Instruction*> DefUseManager::GetAnnotations(uint32_t id) const {
|
2016-08-29 22:05:24 +00:00
|
|
|
std::vector<ir::Instruction*> annos;
|
|
|
|
const auto* uses = GetUses(id);
|
2016-08-20 03:17:44 +00:00
|
|
|
if (!uses) return annos;
|
2016-08-29 22:05:24 +00:00
|
|
|
for (const auto& c : *uses) {
|
|
|
|
if (ir::IsAnnotationInst(c.inst->opcode())) {
|
|
|
|
annos.push_back(c.inst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return annos;
|
|
|
|
}
|
|
|
|
|
2016-08-15 17:41:47 +00:00
|
|
|
void DefUseManager::AnalyzeDefUse(ir::Module* module) {
|
2016-08-16 17:06:03 +00:00
|
|
|
if (!module) return;
|
2016-08-15 17:41:47 +00:00
|
|
|
module->ForEachInst(std::bind(&DefUseManager::AnalyzeInstDefUse, this,
|
|
|
|
std::placeholders::_1));
|
|
|
|
}
|
|
|
|
|
2016-08-16 17:06:03 +00:00
|
|
|
void DefUseManager::ClearInst(ir::Instruction* inst) {
|
|
|
|
auto iter = inst_to_used_ids_.find(inst);
|
|
|
|
if (iter != inst_to_used_ids_.end()) {
|
|
|
|
EraseUseRecordsOfOperandIds(inst);
|
|
|
|
if (inst->result_id() != 0) {
|
|
|
|
id_to_uses_.erase(inst->result_id()); // Remove all uses of this id.
|
|
|
|
id_to_def_.erase(inst->result_id());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-12 14:43:26 +00:00
|
|
|
|
2016-08-16 17:06:03 +00:00
|
|
|
void DefUseManager::EraseUseRecordsOfOperandIds(const ir::Instruction* inst) {
|
2016-08-12 14:43:26 +00:00
|
|
|
// Go through all ids used by this instruction, remove this instruction's
|
|
|
|
// uses of them.
|
2017-09-28 15:14:00 +00:00
|
|
|
//
|
|
|
|
// We cache end iterators to avoid the cost of repeatedly constructing
|
|
|
|
// and destructing their value. This cuts runtime on some examples by
|
|
|
|
// a factor of about 3 (e.g. on Windows debug builds, with many thousands
|
|
|
|
// of instructions).
|
2016-08-16 17:06:03 +00:00
|
|
|
auto iter = inst_to_used_ids_.find(inst);
|
|
|
|
if (iter != inst_to_used_ids_.end()) {
|
2017-09-28 15:14:00 +00:00
|
|
|
// Cache the end iterator on the map. The end iterator on
|
|
|
|
// an unordered map does not get invalidated when erasing an
|
|
|
|
// element.
|
|
|
|
const auto& id_to_uses_end = id_to_uses_.end();
|
2016-08-16 17:06:03 +00:00
|
|
|
for (const auto use_id : iter->second) {
|
|
|
|
auto uses_iter = id_to_uses_.find(use_id);
|
2017-09-28 15:14:00 +00:00
|
|
|
if (uses_iter == id_to_uses_end) continue;
|
2016-08-16 17:06:03 +00:00
|
|
|
auto& uses = uses_iter->second;
|
2017-09-28 15:14:00 +00:00
|
|
|
// Similarly, cache this end iterator. It is not invalidated
|
|
|
|
// by erasure of an element from the list.
|
|
|
|
const auto& uses_end = uses.end();
|
|
|
|
for (auto it = uses.begin(); it != uses_end;) {
|
2016-08-16 17:06:03 +00:00
|
|
|
if (it->inst == inst) {
|
|
|
|
it = uses.erase(it);
|
|
|
|
} else {
|
|
|
|
++it;
|
|
|
|
}
|
2016-08-12 14:43:26 +00:00
|
|
|
}
|
2016-08-16 17:06:03 +00:00
|
|
|
if (uses.empty()) id_to_uses_.erase(use_id);
|
2016-08-12 14:43:26 +00:00
|
|
|
}
|
2016-08-16 17:06:03 +00:00
|
|
|
inst_to_used_ids_.erase(inst);
|
2016-08-12 14:43:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-09 16:24:41 +00:00
|
|
|
bool operator==(const DefUseManager& lhs, const DefUseManager& rhs) {
|
|
|
|
if (lhs.id_to_def_ != rhs.id_to_def_) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto use : lhs.id_to_uses_) {
|
|
|
|
auto rhs_iter = rhs.id_to_uses_.find(use.first);
|
|
|
|
if (rhs_iter == rhs.id_to_uses_.end()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
use.second.sort();
|
|
|
|
UseList rhs_uselist = rhs_iter->second;
|
|
|
|
rhs_uselist.sort();
|
|
|
|
if (use.second != rhs_uselist) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lhs.inst_to_used_ids_ != lhs.inst_to_used_ids_) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-27 21:37:04 +00:00
|
|
|
} // namespace analysis
|
|
|
|
} // namespace opt
|
|
|
|
} // namespace spvtools
|