jak-project/decompiler/IR2/LabelDB.cpp
water111 d9f9e076af
[decompiler] automatically label things when possible (#784)
* improve label system

* clean up menu

* debug menu working, still need to fix tests

* fix tests and clean up
2021-08-29 11:13:06 -04:00

108 lines
3.1 KiB
C++

#include "third-party/fmt/core.h"
#include "LabelDB.h"
namespace decompiler {
std::string LabelInfo::print() const {
if (!known) {
return fmt::format("{} unknown", name);
}
std::string result = fmt::format("{} {} ", name, result_type.print());
if (is_value) {
result += "value ";
} else {
result += "ref ";
}
if (from_user) {
result += "from-config ";
} else {
result += "auto-detected ";
}
if (array_size) {
result += fmt::format("sz: {}", *array_size);
}
return result;
}
LabelDB::LabelDB(const std::unordered_map<std::string, LabelConfigInfo>& config,
const std::vector<DecompilerLabel>& labels,
const DecompilerTypeSystem& dts) {
m_labels_by_offset_into_seg.resize(N_SEG);
// first, copy all labels.
for (size_t i = 0; i < labels.size(); i++) {
const auto& existing_info = labels[i];
LabelInfo info;
info.name = existing_info.name;
info.idx = (int)i;
m_info.push_back(info);
if (!m_labels_by_name.insert({info.name, i}).second) {
throw std::runtime_error(
fmt::format("Label {} appears multiple times, cannot build LabelDB.", info.name));
}
m_labels_by_offset_into_seg.at(existing_info.target_segment)[existing_info.offset] = (int)i;
}
assert(m_labels_by_name.size() == labels.size());
size_t total_from_offsets = 0;
for (int i = 0; i < N_SEG; i++) {
total_from_offsets += m_labels_by_offset_into_seg[i].size();
}
assert(total_from_offsets == labels.size());
// now config
for (const auto& config_it : config) {
const auto& info_it = m_labels_by_name.find(config_it.first);
if (info_it == m_labels_by_name.end()) {
throw std::runtime_error(
fmt::format("Config has an entry for label {}, but it does not exist.", config_it.first));
}
auto& info = m_info.at(info_it->second);
if (info.from_user) {
throw std::runtime_error(
fmt::format("Config has multiple entries for label {}.", config_it.first));
}
info.from_user = true;
info.known = true;
info.result_type = dts.parse_type_spec(config_it.second.type_name);
info.is_value = config_it.second.is_value;
info.array_size = config_it.second.array_size;
}
}
const LabelInfo& LabelDB::lookup(int idx) const {
return m_info.at(idx);
}
const LabelInfo& LabelDB::lookup(const std::string& name) const {
return lookup(m_labels_by_name.at(name));
}
LabelInfo LabelDB::set_and_get_previous(int idx,
const TypeSpec& type,
bool is_value,
std::optional<int> array_size) {
LabelInfo result = m_info.at(idx);
LabelInfo& mod = m_info.at(idx);
mod.result_type = type;
mod.is_value = is_value;
mod.array_size = array_size;
mod.from_user = false;
mod.known = true;
return result;
}
int LabelDB::get_index_by_offset(int seg, int offset) const {
return m_labels_by_offset_into_seg.at(seg).at(offset);
}
int LabelDB::get_index_by_name(const std::string& name) const {
return m_labels_by_name.at(name);
}
} // namespace decompiler