Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Decompilation] Fixes to compiler/decompiler for gcommon #227

Merged
merged 14 commits into from
Feb 6, 2021
2 changes: 1 addition & 1 deletion common/util/FileUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ bool create_dir_if_needed(const std::string& path) {
return false;
}

void write_binary_file(const std::string& name, void* data, size_t size) {
void write_binary_file(const std::string& name, const void* data, size_t size) {
FILE* fp = fopen(name.c_str(), "wb");
if (!fp) {
throw std::runtime_error("couldn't open file " + name);
Expand Down
2 changes: 1 addition & 1 deletion common/util/FileUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace file_util {
std::string get_project_path();
std::string get_file_path(const std::vector<std::string>& input);
bool create_dir_if_needed(const std::string& path);
void write_binary_file(const std::string& name, void* data, size_t size);
void write_binary_file(const std::string& name, const void* data, size_t size);
void write_rgba_png(const std::string& name, void* data, int w, int h);
void write_text_file(const std::string& file_name, const std::string& text);
std::vector<uint8_t> read_binary_file(const std::string& filename);
Expand Down
2 changes: 1 addition & 1 deletion common/versions.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
namespace versions {
// language version (OpenGOAL)
constexpr s32 GOAL_VERSION_MAJOR = 0;
constexpr s32 GOAL_VERSION_MINOR = 5;
constexpr s32 GOAL_VERSION_MINOR = 6;

// these versions are from the game
constexpr u32 ART_FILE_VERSION = 6;
Expand Down
3 changes: 3 additions & 0 deletions decompiler/IR2/AtomicOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,13 @@ class IR2_Condition {
const SimpleAtom& src(int i) const { return m_src[i]; }
ConditionElement* get_as_form(FormPool& pool, const Env& env, int my_idx) const;
void collect_vars(VariableSet& vars) const;
void make_flipped() { m_flipped_eval = true; }
bool flipped() const { return m_flipped_eval; }

private:
Kind m_kind = Kind::INVALID;
SimpleAtom m_src[2];
bool m_flipped_eval = false;
};

std::string get_condition_kind_name(IR2_Condition::Kind kind);
Expand Down
15 changes: 12 additions & 3 deletions decompiler/IR2/AtomicOpForm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ ConditionElement* IR2_Condition::get_as_form(FormPool& pool, const Env& env, int
for (int i = 0; i < get_condition_num_args(m_kind); i++) {
vars[i] = m_src[i];
}
return pool.alloc_element<ConditionElement>(m_kind, vars[0], vars[1], consumed);
return pool.alloc_element<ConditionElement>(m_kind, vars[0], vars[1], consumed, m_flipped_eval);
}

FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
Expand Down Expand Up @@ -90,6 +90,13 @@ FormElement* SetVarConditionOp::get_as_form(FormPool& pool, const Env& env) cons

FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
if (env.has_type_analysis()) {
if (m_addr.is_identity() && m_addr.get_arg(0).is_sym_val()) {
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_value.as_expr(),
m_my_idx);
auto src = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_addr, m_my_idx);
return pool.alloc_element<SetFormFormElement>(src, val);
}

IR2_RegOffset ro;
if (get_as_reg_offset(m_addr, &ro)) {
auto& input_type = env.get_types_before_op(m_my_idx).get(ro.reg);
Expand Down Expand Up @@ -238,8 +245,10 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const {
}
assert(rd.tokens.back().kind == FieldReverseLookupOutput::Token::Kind::VAR_IDX);

auto load = pool.alloc_single_element_form<ArrayFieldAccess>(nullptr, ro.var, tokens,
input_type.get_multiplier());
// we pass along the register offset because code generation seems to be a bit
// different in different cases.
auto load = pool.alloc_single_element_form<ArrayFieldAccess>(
nullptr, ro.var, tokens, input_type.get_multiplier(), ro.offset);
return pool.alloc_element<SetVarElement>(m_dst, load, true);
}
}
Expand Down
63 changes: 1 addition & 62 deletions decompiler/IR2/Env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,67 +57,6 @@ std::string Env::print_local_var_types(const Form* top_level_form) const {
entries.push_back(fmt::format("{}: {}", x.name(), x.type.typespec().print()));
}

if (top_level_form) {
VariableSet var_set;
top_level_form->collect_vars(var_set);

// we want to sort them for easier reading:
std::vector<std::pair<RegId, Variable>> vars;

for (auto& x : var_set) {
vars.push_back(std::make_pair(get_ssa_var(x), x));
}

std::sort(vars.begin(), vars.end(),
[](const std::pair<RegId, Variable>& a, const std::pair<RegId, Variable>& b) {
return a.first < b.first;
});

RegId* prev = nullptr;
for (auto& x : vars) {
// sorted by ssa var and there are likely duplicates of Variables and SSA vars, only print
// unique ssa variables.
if (prev && x.first == *prev) {
continue;
}
prev = &x.first;
auto& map = x.second.mode() == VariableMode::WRITE ? m_var_names.write_vars.at(x.second.reg())
: m_var_names.read_vars.at(x.second.reg());
auto& info = map.at(x.first.id);

if (info.initialized) {
entries.push_back(fmt::format("{}: {}", info.name(), info.type.typespec().print()));
} else {
assert(false);
}
}
} else {
std::unordered_map<Register, std::unordered_set<int>, Register::hash> printed;

for (auto& reg_info : m_var_names.read_vars) {
auto& reg_printed = printed[reg_info.first];
for (int var_id = 0; var_id < int(reg_info.second.size()); var_id++) {
auto& info = reg_info.second.at(var_id);
if (info.initialized) {
reg_printed.insert(var_id);
entries.push_back(fmt::format("{}: {}", info.name(), info.type.typespec().print()));
}
}
}

for (auto& reg_info : m_var_names.write_vars) {
auto& reg_printed = printed[reg_info.first];
for (int var_id = 0; var_id < int(reg_info.second.size()); var_id++) {
auto& info = reg_info.second.at(var_id);
if (info.initialized) {
if (reg_printed.find(var_id) == reg_printed.end()) {
entries.push_back(fmt::format("{}: {}", info.name(), info.type.typespec().print()));
}
}
}
}
}

int max_len = 0;
for (auto& entry : entries) {
if (int(entry.length()) > max_len) {
Expand Down Expand Up @@ -228,7 +167,7 @@ goos::Object Env::local_var_type_list(const Form* top_level_form,
int count = 0;
for (auto& x : vars) {
if (x.reg_id.reg.get_kind() == Reg::GPR && x.reg_id.reg.get_gpr() < Reg::A0 + nargs_to_ignore &&
x.reg_id.reg.get_gpr() >= Reg::A0) {
x.reg_id.reg.get_gpr() >= Reg::A0 && x.reg_id.id == 0) {
continue;
}
count++;
Expand Down
40 changes: 31 additions & 9 deletions decompiler/IR2/Form.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,9 @@ void AtomicOpElement::get_modified_regs(RegSet& regs) const {
ConditionElement::ConditionElement(IR2_Condition::Kind kind,
std::optional<SimpleAtom> src0,
std::optional<SimpleAtom> src1,
RegSet consumed)
: m_kind(kind), m_consumed(std::move(consumed)) {
RegSet consumed,
bool flipped)
: m_kind(kind), m_consumed(std::move(consumed)), m_flipped(flipped) {
m_src[0] = src0;
m_src[1] = src1;
}
Expand Down Expand Up @@ -768,7 +769,7 @@ goos::Object CondNoElseElement::to_form(const Env& env) const {
for (auto& e : entries) {
std::vector<goos::Object> entry;
entry.push_back(e.condition->to_form_as_condition(env));
entries.front().body->inline_forms(list, env);
e.body->inline_forms(entry, env);
list.push_back(pretty_print::build_list(entry));
}
return pretty_print::build_list(list);
Expand Down Expand Up @@ -1067,10 +1068,12 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "lognor";
case FixedOperatorKind::LOGNOT:
return "lognot";
case FixedOperatorKind::SLL:
return "sll";
case FixedOperatorKind::SRL:
return "srl";
case FixedOperatorKind::SHL:
return "shl";
case FixedOperatorKind::SHR:
return "shr";
case FixedOperatorKind::SAR:
return "sar";
case FixedOperatorKind::CAR:
return "car";
case FixedOperatorKind::CDR:
Expand All @@ -1079,6 +1082,21 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "new";
case FixedOperatorKind::OBJECT_NEW:
return "object-new";
case FixedOperatorKind::TYPE_NEW:
return "type-new";

case FixedOperatorKind::LT:
return "<";
case FixedOperatorKind::GT:
return ">";
case FixedOperatorKind::LEQ:
return "<=";
case FixedOperatorKind::GEQ:
return ">=";
case FixedOperatorKind::EQ:
return "=";
case FixedOperatorKind::NEQ:
return "!=";
default:
assert(false);
}
Expand Down Expand Up @@ -1323,8 +1341,12 @@ void DynamicMethodAccess::get_modified_regs(RegSet&) const {}
/////////////////////////////
ArrayFieldAccess::ArrayFieldAccess(Variable source,
const std::vector<DerefToken>& deref_tokens,
int expected_stride)
: m_source(source), m_deref_tokens(deref_tokens), m_expected_stride(expected_stride) {}
int expected_stride,
int constant_offset)
: m_source(source),
m_deref_tokens(deref_tokens),
m_expected_stride(expected_stride),
m_constant_offset(constant_offset) {}

goos::Object ArrayFieldAccess::to_form(const Env& env) const {
std::vector<goos::Object> elts;
Expand Down
Loading