#include "source/opt/value_number_table.h"
#include <algorithm>
#include "source/opt/cfg.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace opt {
uint32_t ValueNumberTable::GetValueNumber(Instruction* inst) const {
assert(inst->result_id() != 0 &&
"inst must have a result id to get a value number.");
auto result_id_to_val = id_to_value_.find(inst->result_id());
if (result_id_to_val != id_to_value_.end()) {
return result_id_to_val->second;
}
return 0;
}
uint32_t ValueNumberTable::GetValueNumber(uint32_t id) const {
return GetValueNumber(context()->get_def_use_mgr()->GetDef(id));
}
uint32_t ValueNumberTable::AssignValueNumber(Instruction* inst) {
uint32_t value = GetValueNumber(inst);
if (value != 0) {
return value;
}
if (!context()->IsCombinatorInstruction(inst) &&
!inst->IsCommonDebugInstr()) {
value = TakeNextValueNumber();
id_to_value_[inst->result_id()] = value;
return value;
}
switch (inst->opcode()) {
case spv::Op::OpSampledImage:
case spv::Op::OpImage:
case spv::Op::OpVariable:
value = TakeNextValueNumber();
id_to_value_[inst->result_id()] = value;
return value;
default:
break;
}
if (inst->IsLoad() && !inst->IsReadOnlyLoad()) {
value = TakeNextValueNumber();
id_to_value_[inst->result_id()] = value;
return value;
}
analysis::DecorationManager* dec_mgr = context()->get_decoration_mgr();
if (inst->opcode() == spv::Op::OpCopyObject &&
dec_mgr->HaveTheSameDecorations(inst->result_id(),
inst->GetSingleWordInOperand(0))) {
value = GetValueNumber(inst->GetSingleWordInOperand(0));
if (value != 0) {
id_to_value_[inst->result_id()] = value;
return value;
}
}
if (inst->opcode() == spv::Op::OpPhi && inst->NumInOperands() > 0 &&
dec_mgr->HaveTheSameDecorations(inst->result_id(),
inst->GetSingleWordInOperand(0))) {
value = GetValueNumber(inst->GetSingleWordInOperand(0));
if (value != 0) {
for (uint32_t op = 2; op < inst->NumInOperands(); op += 2) {
if (value != GetValueNumber(inst->GetSingleWordInOperand(op))) {
value = 0;
break;
}
}
if (value != 0) {
id_to_value_[inst->result_id()] = value;
return value;
}
}
}
Instruction value_ins(context(), inst->opcode(), inst->type_id(),
inst->result_id(), {});
for (uint32_t o = 0; o < inst->NumInOperands(); ++o) {
const Operand& op = inst->GetInOperand(o);
if (spvIsIdType(op.type)) {
uint32_t id_value = op.words[0];
auto use_id_to_val = id_to_value_.find(id_value);
if (use_id_to_val != id_to_value_.end()) {
id_value = (1 << 31) | use_id_to_val->second;
}
value_ins.AddOperand(Operand(op.type, {id_value}));
} else {
value_ins.AddOperand(Operand(op.type, op.words));
}
}
auto value_iterator = instruction_to_value_.find(value_ins);
if (value_iterator != instruction_to_value_.end()) {
value = id_to_value_[value_iterator->first.result_id()];
id_to_value_[inst->result_id()] = value;
return value;
}
value = TakeNextValueNumber();
id_to_value_[inst->result_id()] = value;
instruction_to_value_[value_ins] = value;
return value;
}
void ValueNumberTable::BuildDominatorTreeValueNumberTable() {
for (auto& inst : context()->annotations()) {
if (inst.result_id() != 0) {
AssignValueNumber(&inst);
}
}
for (auto& inst : context()->capabilities()) {
if (inst.result_id() != 0) {
AssignValueNumber(&inst);
}
}
for (auto& inst : context()->types_values()) {
if (inst.result_id() != 0) {
AssignValueNumber(&inst);
}
}
for (auto& inst : context()->module()->ext_inst_imports()) {
if (inst.result_id() != 0) {
AssignValueNumber(&inst);
}
}
for (auto& inst : context()->module()->ext_inst_debuginfo()) {
if (inst.result_id() != 0) {
AssignValueNumber(&inst);
}
}
for (Function& func : *context()->module()) {
for (BasicBlock& block : func) {
for (Instruction& inst : block) {
if (inst.result_id() != 0) {
AssignValueNumber(&inst);
}
}
}
}
}
bool ComputeSameValue::operator()(const Instruction& lhs,
const Instruction& rhs) const {
if (lhs.result_id() == 0 || rhs.result_id() == 0) {
return false;
}
if (lhs.opcode() != rhs.opcode()) {
return false;
}
if (lhs.type_id() != rhs.type_id()) {
return false;
}
if (lhs.NumInOperands() != rhs.NumInOperands()) {
return false;
}
for (uint32_t i = 0; i < lhs.NumInOperands(); ++i) {
if (lhs.GetInOperand(i) != rhs.GetInOperand(i)) {
return false;
}
}
return lhs.context()->get_decoration_mgr()->HaveTheSameDecorations(
lhs.result_id(), rhs.result_id());
}
std::size_t ValueTableHash::operator()(const Instruction& inst) const {
std::u32string h;
h.push_back(uint32_t(inst.opcode()));
h.push_back(inst.type_id());
for (uint32_t i = 0; i < inst.NumInOperands(); ++i) {
const auto& opnd = inst.GetInOperand(i);
for (uint32_t word : opnd.words) {
h.push_back(word);
}
}
return std::hash<std::u32string>()(h);
}
}
}