remove useless sets (#252)

This commit is contained in:
water111
2021-02-11 14:35:28 -05:00
committed by GitHub
parent 43c1d223a6
commit d9a8f28e52
16 changed files with 423 additions and 266 deletions
+2 -5
View File
@@ -5,9 +5,6 @@
* Version numbers for GOAL Language, Kernel, etc...
*/
#ifndef JAK1_VERSIONS_H
#define JAK1_VERSIONS_H
#include "common/common_types.h"
namespace versions {
@@ -15,6 +12,8 @@ namespace versions {
constexpr s32 GOAL_VERSION_MAJOR = 0;
constexpr s32 GOAL_VERSION_MINOR = 6;
constexpr int DECOMPILER_VERSION = 1;
// these versions are from the game
constexpr u32 ART_FILE_VERSION = 6;
constexpr u32 LEVEL_FILE_VERSION = 30;
@@ -26,5 +25,3 @@ constexpr u32 TX_PAGE_VERSION = 7;
// GOAL kernel version (OpenGOAL changes this version from the game's version)
constexpr int KERNEL_VERSION_MAJOR = 2;
constexpr int KERNEL_VERSION_MINOR = 0;
#endif // JAK1_VERSIONS_H
+21 -2
View File
@@ -77,11 +77,30 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
}
}
// create element
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_src, m_my_idx);
auto result = pool.alloc_element<SetVarElement>(m_dst, source, is_sequence_point());
if (m_src.kind() == SimpleExpression::Kind::IDENTITY) {
if (env.has_local_vars() && env.op_id_is_eliminated_coloring_move(m_my_idx)) {
// do some analysis to look for coloring moves which are already eliminated,
// dead sets, and dead set falses.
if (m_src.kind() == SimpleExpression::Kind::IDENTITY && env.has_local_vars() &&
env.has_reg_use()) {
if (env.op_id_is_eliminated_coloring_move(m_my_idx)) {
result->eliminate_as_coloring_move();
} else if (m_src.get_arg(0).is_var()) {
auto& src_var = m_src.get_arg(0).var();
auto& ri = env.reg_use().op.at(m_my_idx);
if (ri.consumes.find(src_var.reg()) != ri.consumes.end() &&
ri.written_and_unused.find(dst().reg()) != ri.written_and_unused.end()) {
result->mark_as_dead_set();
// fmt::print("marked {} as dead set\n", to_string(env));
}
} else if (m_src.get_arg(0).is_sym_ptr() && m_src.get_arg(0).get_str() == "#f") {
auto& ri = env.reg_use().op.at(m_my_idx);
if (ri.written_and_unused.find(dst().reg()) != ri.written_and_unused.end()) {
result->mark_as_dead_false();
// fmt::print("marked {} as dead set false\n", to_string(env));
}
}
}
+70 -39
View File
@@ -32,10 +32,22 @@ void FormElement::push_to_stack(const Env& env, FormPool&, FormStack&) {
throw std::runtime_error("push_to_stack not implemented for " + to_string(env));
}
goos::Object FormElement::to_form_as_condition(const Env& env) const {
goos::Object FormElement::to_form_as_condition_internal(const Env& env) const {
return to_form(env);
}
bool FormElement::active() const {
return true;
}
goos::Object FormElement::to_form(const Env& env) const {
if (active()) {
return to_form_internal(env);
} else {
return pretty_print::build_list("empty-form");
}
}
///////////////////
// Form
//////////////////
@@ -48,7 +60,13 @@ goos::Object Form::to_form(const Env& env) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("begin"));
for (auto& x : m_elements) {
forms.push_back(x->to_form(env));
if (x->active()) {
forms.push_back(x->to_form_internal(env));
}
}
if (forms.size() == 2) {
return forms.at(1);
}
return pretty_print::build_list(forms);
}
@@ -57,16 +75,18 @@ goos::Object Form::to_form(const Env& env) const {
goos::Object Form::to_form_as_condition(const Env& env) const {
assert(!m_elements.empty());
if (m_elements.size() == 1) {
return m_elements.front()->to_form_as_condition(env);
return m_elements.front()->to_form_as_condition_internal(env);
} else {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("begin"));
for (size_t i = 0; i < m_elements.size(); i++) {
const auto& x = m_elements.at(i);
if (i == m_elements.size() - 1) {
forms.push_back(x->to_form_as_condition(env));
forms.push_back(x->to_form_as_condition_internal(env));
} else {
forms.push_back(x->to_form(env));
if (x->active()) {
forms.push_back(x->to_form_internal(env));
}
}
}
@@ -80,7 +100,9 @@ std::string Form::to_string(const Env& env) const {
void Form::inline_forms(std::vector<goos::Object>& forms, const Env& env) const {
for (auto& x : m_elements) {
forms.push_back(x->to_form(env));
if (x->active()) {
forms.push_back(x->to_form_internal(env));
}
}
}
@@ -116,7 +138,7 @@ void Form::get_modified_regs(RegSet& regs) const {
SimpleExpressionElement::SimpleExpressionElement(SimpleExpression expr, int my_idx)
: m_expr(std::move(expr)), m_my_idx(my_idx) {}
goos::Object SimpleExpressionElement::to_form(const Env& env) const {
goos::Object SimpleExpressionElement::to_form_internal(const Env& env) const {
return m_expr.to_form(env.file->labels, env);
}
@@ -144,7 +166,7 @@ void SimpleExpressionElement::get_modified_regs(RegSet& regs) const {
StoreElement::StoreElement(const StoreOp* op) : m_op(op) {}
goos::Object StoreElement::to_form(const Env& env) const {
goos::Object StoreElement::to_form_internal(const Env& env) const {
return m_op->to_form(env.file->labels, env);
}
@@ -171,7 +193,7 @@ LoadSourceElement::LoadSourceElement(Form* addr, int size, LoadVarOp::Kind kind)
m_addr->parent_element = this;
}
goos::Object LoadSourceElement::to_form(const Env& env) const {
goos::Object LoadSourceElement::to_form_internal(const Env& env) const {
switch (m_kind) {
case LoadVarOp::Kind::FLOAT:
assert(m_size == 4);
@@ -230,7 +252,7 @@ void LoadSourceElement::get_modified_regs(RegSet& regs) const {
SimpleAtomElement::SimpleAtomElement(const SimpleAtom& atom) : m_atom(atom) {}
goos::Object SimpleAtomElement::to_form(const Env& env) const {
goos::Object SimpleAtomElement::to_form_internal(const Env& env) const {
return m_atom.to_form(env.file->labels, env);
}
@@ -257,7 +279,7 @@ SetVarElement::SetVarElement(const Variable& var, Form* value, bool is_sequence_
value->parent_element = this;
}
goos::Object SetVarElement::to_form(const Env& env) const {
goos::Object SetVarElement::to_form_internal(const Env& env) const {
return pretty_print::build_list("set!", m_dst.to_form(env), m_src->to_form(env));
}
@@ -284,6 +306,14 @@ void SetVarElement::get_modified_regs(RegSet& regs) const {
m_src->get_modified_regs(regs);
}
bool SetVarElement::active() const {
if (is_eliminated_coloring_move() || is_dead_false_set()) {
return false;
} else {
return true;
}
}
/////////////////////////////
// SetFormFormElement
/////////////////////////////
@@ -293,7 +323,7 @@ SetFormFormElement::SetFormFormElement(Form* dst, Form* src) : m_dst(dst), m_src
m_src->parent_element = this;
}
goos::Object SetFormFormElement::to_form(const Env& env) const {
goos::Object SetFormFormElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms = {pretty_print::to_symbol("set!"), m_dst->to_form(env),
m_src->to_form(env)};
return pretty_print::build_list(forms);
@@ -328,7 +358,7 @@ void SetFormFormElement::get_modified_regs(RegSet& regs) const {
AtomicOpElement::AtomicOpElement(const AtomicOp* op) : m_op(op) {}
goos::Object AtomicOpElement::to_form(const Env& env) const {
goos::Object AtomicOpElement::to_form_internal(const Env& env) const {
return m_op->to_form(env.file->labels, env);
}
@@ -358,7 +388,7 @@ void AtomicOpElement::get_modified_regs(RegSet& regs) const {
AsmOpElement::AsmOpElement(const AsmOp* op) : m_op(op) {}
goos::Object AsmOpElement::to_form(const Env& env) const {
goos::Object AsmOpElement::to_form_internal(const Env& env) const {
return m_op->to_form(env.file->labels, env);
}
@@ -396,7 +426,7 @@ ConditionElement::ConditionElement(IR2_Condition::Kind kind,
m_src[1] = src1;
}
goos::Object ConditionElement::to_form(const Env& env) const {
goos::Object ConditionElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol(get_condition_kind_name(m_kind)));
for (int i = 0; i < get_condition_num_args(m_kind); i++) {
@@ -409,11 +439,11 @@ goos::Object ConditionElement::to_form(const Env& env) const {
}
}
goos::Object ConditionElement::to_form_as_condition(const Env& env) const {
goos::Object ConditionElement::to_form_as_condition_internal(const Env& env) const {
if (m_kind == IR2_Condition::Kind::TRUTHY) {
return m_src[0]->to_form(env.file->labels, env);
} else {
return to_form(env);
return to_form_internal(env);
}
}
@@ -445,7 +475,7 @@ void ConditionElement::get_modified_regs(RegSet& regs) const {
FunctionCallElement::FunctionCallElement(const CallOp* op) : m_op(op) {}
goos::Object FunctionCallElement::to_form(const Env& env) const {
goos::Object FunctionCallElement::to_form_internal(const Env& env) const {
return m_op->to_form(env.file->labels, env);
}
@@ -475,7 +505,7 @@ void FunctionCallElement::get_modified_regs(RegSet& regs) const {
BranchElement::BranchElement(const BranchOp* op) : m_op(op) {}
goos::Object BranchElement::to_form(const Env& env) const {
goos::Object BranchElement::to_form_internal(const Env& env) const {
return m_op->to_form(env.file->labels, env);
}
@@ -503,7 +533,7 @@ void BranchElement::get_modified_regs(RegSet& regs) const {
// ReturnElement
/////////////////////////////
goos::Object ReturnElement::to_form(const Env& env) const {
goos::Object ReturnElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("return"));
forms.push_back(return_code->to_form(env));
@@ -546,7 +576,7 @@ void ReturnElement::get_modified_regs(RegSet& regs) const {
// BreakElement
/////////////////////////////
goos::Object BreakElement::to_form(const Env& env) const {
goos::Object BreakElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("break"));
forms.push_back(pretty_print::build_list(return_code->to_form(env)));
@@ -580,7 +610,7 @@ void BreakElement::get_modified_regs(RegSet& regs) const {
// CondWithElseElement
/////////////////////////////
goos::Object CondWithElseElement::to_form(const Env& env) const {
goos::Object CondWithElseElement::to_form_internal(const Env& env) const {
// for now we only turn it into an if statement if both cases won't require a begin at the top
// level. I think it is more common to write these as a two-case cond instead of an if with begin.
if (entries.size() == 1 && entries.front().body->is_single_element() &&
@@ -645,7 +675,7 @@ void CondWithElseElement::get_modified_regs(RegSet& regs) const {
// EmptyElement
/////////////////////////////
goos::Object EmptyElement::to_form(const Env&) const {
goos::Object EmptyElement::to_form_internal(const Env&) const {
return pretty_print::build_list("empty");
}
@@ -668,7 +698,7 @@ void WhileElement::apply(const std::function<void(FormElement*)>& f) {
condition->apply(f);
}
goos::Object WhileElement::to_form(const Env& env) const {
goos::Object WhileElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> list;
list.push_back(pretty_print::to_symbol("while"));
list.push_back(condition->to_form_as_condition(env));
@@ -702,7 +732,7 @@ void UntilElement::apply(const std::function<void(FormElement*)>& f) {
condition->apply(f);
}
goos::Object UntilElement::to_form(const Env& env) const {
goos::Object UntilElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> list;
list.push_back(pretty_print::to_symbol("until"));
list.push_back(condition->to_form_as_condition(env));
@@ -750,7 +780,7 @@ void ShortCircuitElement::apply_form(const std::function<void(Form*)>& f) {
}
}
goos::Object ShortCircuitElement::to_form(const Env& env) const {
goos::Object ShortCircuitElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms;
switch (kind) {
case UNKNOWN:
@@ -788,7 +818,7 @@ void ShortCircuitElement::get_modified_regs(RegSet& regs) const {
// CondNoElseElement
/////////////////////////////
goos::Object CondNoElseElement::to_form(const Env& env) const {
goos::Object CondNoElseElement::to_form_internal(const Env& env) const {
if (entries.size() == 1 && entries.front().body->is_single_element()) {
// print as an if statement if we can put the body in a single form.
std::vector<goos::Object> list;
@@ -854,7 +884,7 @@ void CondNoElseElement::get_modified_regs(RegSet& regs) const {
AbsElement::AbsElement(Variable _source, RegSet _consumed)
: source(_source), consumed(std::move(_consumed)) {}
goos::Object AbsElement::to_form(const Env& env) const {
goos::Object AbsElement::to_form_internal(const Env& env) const {
return pretty_print::build_list("abs", source.to_form(env));
}
@@ -885,7 +915,7 @@ AshElement::AshElement(Variable _shift_amount,
is_signed(_is_signed),
consumed(_consumed) {}
goos::Object AshElement::to_form(const Env& env) const {
goos::Object AshElement::to_form_internal(const Env& env) const {
return pretty_print::build_list(pretty_print::to_symbol(is_signed ? "ash.si" : "ash.ui"),
value.to_form(env), shift_amount.to_form(env));
}
@@ -912,7 +942,7 @@ TypeOfElement::TypeOfElement(Form* _value, std::optional<Variable> _clobber)
value->parent_element = this;
}
goos::Object TypeOfElement::to_form(const Env& env) const {
goos::Object TypeOfElement::to_form_internal(const Env& env) const {
return pretty_print::build_list("rtype-of", value->to_form(env));
}
@@ -942,7 +972,7 @@ ConditionalMoveFalseElement::ConditionalMoveFalseElement(Variable _dest,
source->parent_element = this;
}
goos::Object ConditionalMoveFalseElement::to_form(const Env& env) const {
goos::Object ConditionalMoveFalseElement::to_form_internal(const Env& env) const {
return pretty_print::build_list(on_zero ? "cmove-#f-zero" : "cmove-#f-nonzero", dest.to_form(env),
source->to_form(env));
}
@@ -1125,7 +1155,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "object-new";
case FixedOperatorKind::TYPE_NEW:
return "type-new";
case FixedOperatorKind::CONS:
return "cons";
case FixedOperatorKind::LT:
return "<";
case FixedOperatorKind::GT:
@@ -1178,7 +1209,7 @@ GenericElement::GenericElement(GenericOperator op, std::vector<Form*> forms)
}
}
goos::Object GenericElement::to_form(const Env& env) const {
goos::Object GenericElement::to_form_internal(const Env& env) const {
if (m_head.kind() == GenericOperator::Kind::CONDITION_OPERATOR &&
m_head.condition_kind() == IR2_Condition::Kind::TRUTHY) {
assert(m_elts.size() == 1);
@@ -1231,7 +1262,7 @@ CastElement::CastElement(TypeSpec type, Form* source, bool numeric)
source->parent_element = this;
}
goos::Object CastElement::to_form(const Env& env) const {
goos::Object CastElement::to_form_internal(const Env& env) const {
return pretty_print::build_list(m_numeric ? "the" : "the-as", m_type.print(),
m_source->to_form(env));
}
@@ -1375,7 +1406,7 @@ DerefElement::DerefElement(Form* base, bool is_addr_of, std::vector<DerefToken>
}
}
goos::Object DerefElement::to_form(const Env& env) const {
goos::Object DerefElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms = {pretty_print::to_symbol(m_is_addr_of ? "&->" : "->"),
m_base->to_form(env)};
for (auto& tok : m_tokens) {
@@ -1419,7 +1450,7 @@ void DerefElement::get_modified_regs(RegSet& regs) const {
DynamicMethodAccess::DynamicMethodAccess(Variable source) : m_source(source) {}
goos::Object DynamicMethodAccess::to_form(const Env& env) const {
goos::Object DynamicMethodAccess::to_form_internal(const Env& env) const {
return pretty_print::build_list("dyn-method-access", m_source.to_form(env));
}
@@ -1447,7 +1478,7 @@ ArrayFieldAccess::ArrayFieldAccess(Variable source,
m_expected_stride(expected_stride),
m_constant_offset(constant_offset) {}
goos::Object ArrayFieldAccess::to_form(const Env& env) const {
goos::Object ArrayFieldAccess::to_form_internal(const Env& env) const {
std::vector<goos::Object> elts;
elts.push_back(pretty_print::to_symbol("dynamic-array-field-access"));
elts.push_back(m_source.to_form(env));
@@ -1492,7 +1523,7 @@ GetMethodElement::GetMethodElement(Form* in, std::string name, bool is_object)
in->parent_element = this;
}
goos::Object GetMethodElement::to_form(const Env& env) const {
goos::Object GetMethodElement::to_form_internal(const Env& env) const {
return pretty_print::build_list(m_is_object ? "method-of-object" : "method-of-type",
m_in->to_form(env), m_name);
}
@@ -1520,7 +1551,7 @@ void GetMethodElement::get_modified_regs(RegSet& regs) const {
StringConstantElement::StringConstantElement(const std::string& value) : m_value(value) {}
goos::Object StringConstantElement::to_form(const Env&) const {
goos::Object StringConstantElement::to_form_internal(const Env&) const {
return goos::StringObject::make_new(m_value);
}
+59 -34
View File
@@ -21,14 +21,17 @@ class FormElement {
public:
Form* parent_form = nullptr;
virtual goos::Object to_form(const Env& env) const = 0;
virtual goos::Object to_form_as_condition(const Env& env) const;
goos::Object to_form(const Env& env) const;
virtual goos::Object to_form_internal(const Env& env) const = 0;
virtual goos::Object to_form_as_condition_internal(const Env& env) const;
virtual ~FormElement() = default;
virtual void apply(const std::function<void(FormElement*)>& f) = 0;
virtual void apply_form(const std::function<void(Form*)>& f) = 0;
virtual bool is_sequence_point() const { return true; }
virtual void collect_vars(VariableSet& vars) const = 0;
virtual void get_modified_regs(RegSet& regs) const = 0;
virtual bool active() const;
std::string to_string(const Env& env) const;
bool has_side_effects();
@@ -52,11 +55,12 @@ class SimpleExpressionElement : public FormElement {
public:
explicit SimpleExpressionElement(SimpleExpression expr, int my_idx);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
bool is_sequence_point() const override;
void collect_vars(VariableSet& vars) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
// void push_to_stack(const Env& env, FormStack& stack) override;
void update_from_stack(const Env& env,
FormPool& pool,
@@ -150,7 +154,7 @@ class StoreElement : public FormElement {
public:
explicit StoreElement(const StoreOp* op);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -169,7 +173,7 @@ class StoreElement : public FormElement {
class LoadSourceElement : public FormElement {
public:
LoadSourceElement(Form* addr, int size, LoadVarOp::Kind kind);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -196,12 +200,18 @@ class LoadSourceElement : public FormElement {
class SimpleAtomElement : public FormElement {
public:
explicit SimpleAtomElement(const SimpleAtom& var);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
void get_modified_regs(RegSet& regs) const override;
const SimpleAtom& atom() const { return m_atom; }
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
void update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) override;
// void push_to_stack(const Env& env, FormStack& stack) override;
private:
@@ -214,7 +224,7 @@ class SimpleAtomElement : public FormElement {
class SetVarElement : public FormElement {
public:
SetVarElement(const Variable& var, Form* value, bool is_sequence_point);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
bool is_sequence_point() const override;
@@ -226,6 +236,7 @@ class SetVarElement : public FormElement {
std::vector<FormElement*>* result,
bool allow_side_effects) override;
void get_modified_regs(RegSet& regs) const override;
bool active() const override;
const Variable& dst() const { return m_dst; }
const Form* src() const { return m_src; }
@@ -233,11 +244,25 @@ class SetVarElement : public FormElement {
bool is_eliminated_coloring_move() const { return m_is_eliminated_coloring_move; }
void eliminate_as_coloring_move() { m_is_eliminated_coloring_move = true; }
bool is_dead_set() const { return m_is_dead_set; }
void mark_as_dead_set() { m_is_dead_set = true; }
bool is_dead_false_set() const { return m_is_dead_false; }
void mark_as_dead_false() { m_is_dead_false = true; }
private:
Variable m_dst;
Form* m_src = nullptr;
bool m_is_sequence_point = true;
// is this a compiler-inserted move at the beginning of a function
// that should be eliminated?
bool m_is_eliminated_coloring_move = false;
// is this a (set! var expr) which consumes the reg for expr,
// and var is written and unused?
bool m_is_dead_set = false;
// is this a (set! var #f) where the value of #f isn't used?
bool m_is_dead_false = false;
};
/*!
@@ -248,7 +273,7 @@ class SetVarElement : public FormElement {
class SetFormFormElement : public FormElement {
public:
SetFormFormElement(Form* dst, Form* src);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
bool is_sequence_point() const override;
@@ -273,7 +298,7 @@ class SetFormFormElement : public FormElement {
class AtomicOpElement : public FormElement {
public:
explicit AtomicOpElement(const AtomicOp* op);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -291,7 +316,7 @@ class AtomicOpElement : public FormElement {
class AsmOpElement : public FormElement {
public:
explicit AsmOpElement(const AsmOp* op);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -318,8 +343,8 @@ class ConditionElement : public FormElement {
std::optional<SimpleAtom> src1,
RegSet consumed,
bool flipped);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_as_condition(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
goos::Object to_form_as_condition_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -351,7 +376,7 @@ class ConditionElement : public FormElement {
class FunctionCallElement : public FormElement {
public:
explicit FunctionCallElement(const CallOp* op);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -374,7 +399,7 @@ class FunctionCallElement : public FormElement {
class BranchElement : public FormElement {
public:
explicit BranchElement(const BranchOp* op);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -397,7 +422,7 @@ class ReturnElement : public FormElement {
Form* dead_code = nullptr;
ReturnElement(Form* _return_code, Form* _dead_code)
: return_code(_return_code), dead_code(_dead_code) {}
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -432,7 +457,7 @@ class BreakElement : public FormElement {
Form* dead_code = nullptr;
BreakElement(Form* _return_code, Form* _dead_code)
: return_code(_return_code), dead_code(_dead_code) {}
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -466,7 +491,7 @@ class CondWithElseElement : public FormElement {
bool already_rewritten = false;
CondWithElseElement(std::vector<Entry> _entries, Form* _else_ir)
: entries(std::move(_entries)), else_ir(_else_ir) {}
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -485,7 +510,7 @@ class CondWithElseElement : public FormElement {
class EmptyElement : public FormElement {
public:
EmptyElement() = default;
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -501,7 +526,7 @@ class EmptyElement : public FormElement {
class WhileElement : public FormElement {
public:
WhileElement(Form* _condition, Form* _body) : condition(_condition), body(_body) {}
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -520,7 +545,7 @@ class WhileElement : public FormElement {
class UntilElement : public FormElement {
public:
UntilElement(Form* _condition, Form* _body) : condition(_condition), body(_body) {}
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -555,7 +580,7 @@ class ShortCircuitElement : public FormElement {
bool already_rewritten = false;
explicit ShortCircuitElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -587,7 +612,7 @@ class CondNoElseElement : public FormElement {
bool already_rewritten = false;
std::vector<Entry> entries;
explicit CondNoElseElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -601,7 +626,7 @@ class CondNoElseElement : public FormElement {
class AbsElement : public FormElement {
public:
explicit AbsElement(Variable _source, RegSet _consumed);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -631,7 +656,7 @@ class AshElement : public FormElement {
std::optional<Variable> _clobber,
bool _is_signed,
RegSet _consumed);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -652,7 +677,7 @@ class TypeOfElement : public FormElement {
Form* value;
std::optional<Variable> clobber;
TypeOfElement(Form* _value, std::optional<Variable> _clobber);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -688,7 +713,7 @@ class ConditionalMoveFalseElement : public FormElement {
Form* source = nullptr;
bool on_zero = false;
ConditionalMoveFalseElement(Variable _dest, Form* _source, bool _on_zero);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -752,7 +777,7 @@ class GenericElement : public FormElement {
GenericElement(GenericOperator op, Form* arg0, Form* arg1);
GenericElement(GenericOperator op, std::vector<Form*> forms);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -775,7 +800,7 @@ class GenericElement : public FormElement {
class CastElement : public FormElement {
public:
explicit CastElement(TypeSpec type, Form* source, bool numeric = false);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -837,7 +862,7 @@ class DerefElement : public FormElement {
public:
DerefElement(Form* base, bool is_addr_of, DerefToken token);
DerefElement(Form* base, bool is_addr_of, std::vector<DerefToken> tokens);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -862,7 +887,7 @@ class DerefElement : public FormElement {
class DynamicMethodAccess : public FormElement {
public:
explicit DynamicMethodAccess(Variable source);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -883,7 +908,7 @@ class ArrayFieldAccess : public FormElement {
const std::vector<DerefToken>& deref_tokens,
int expected_stride,
int constant_offset);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -904,7 +929,7 @@ class ArrayFieldAccess : public FormElement {
class GetMethodElement : public FormElement {
public:
GetMethodElement(Form* in, std::string name, bool is_object);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -919,7 +944,7 @@ class GetMethodElement : public FormElement {
class StringConstantElement : public FormElement {
public:
StringConstantElement(const std::string& value);
goos::Object to_form(const Env& env) const override;
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override;
@@ -958,7 +983,7 @@ class Form {
}
bool is_single_element() const { return m_elements.size() == 1; }
FormElement* operator[](int idx) { return m_elements.at(idx); }
FormElement* at(int idx) { return m_elements.at(idx); }
FormElement*& at(int idx) { return m_elements.at(idx); }
const FormElement* operator[](int idx) const { return m_elements.at(idx); }
int size() const { return int(m_elements.size()); }
FormElement* back() const {
+64 -8
View File
@@ -910,7 +910,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
match_result = match(matcher, temp_form);
if (match_result.matched) {
auto alloc = match_result.maps.strings.at(allocation);
if (alloc != "global" && alloc != "debug") {
if (alloc != "global" && alloc != "debug" && alloc != "process") {
throw std::runtime_error("Unrecognized heap symbol for new: " + alloc);
}
auto type_2 = match_result.maps.strings.at(type_for_arg);
@@ -922,13 +922,25 @@ void FunctionCallElement::update_from_stack(const Env& env,
auto quoted_type = pool.alloc_single_element_form<SimpleAtomElement>(
nullptr, SimpleAtom::make_sym_ptr(type_2));
std::vector<Form*> new_args = dynamic_cast<GenericElement*>(new_form)->elts();
new_args.at(1) = quoted_type;
if (alloc == "global" && type_1 == "pair") {
// cons!
// (new 'global 'pair a b) -> (cons a b)
std::vector<Form*> cons_args = {dynamic_cast<GenericElement*>(new_form)->elts().at(2),
dynamic_cast<GenericElement*>(new_form)->elts().at(3)};
auto cons_op = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::CONS), cons_args);
result->push_back(cons_op);
return;
} else {
// just normal construction on the heap
std::vector<Form*> new_args = dynamic_cast<GenericElement*>(new_form)->elts();
new_args.at(1) = quoted_type;
auto new_op = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::NEW), new_args);
result->push_back(new_op);
return;
auto new_op = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::NEW), new_args);
result->push_back(new_op);
return;
}
} else {
throw std::runtime_error("Failed to match new method");
}
@@ -1035,6 +1047,7 @@ void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac
void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
if (already_rewritten) {
stack.push_form_element(this, true);
return;
}
for (auto& entry : entries) {
for (auto form : {entry.condition, entry.body}) {
@@ -1057,6 +1070,17 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
}
}
// raise expression.
auto top_condition = entries.front().condition;
if (!top_condition->is_single_element()) {
auto real_condition = top_condition->back();
top_condition->pop_back();
for (auto x : top_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
top_condition->elts() = {real_condition};
}
if (used_as_value) {
stack.push_value_to_reg(final_destination, pool.alloc_single_form(nullptr, this), true);
} else {
@@ -1068,6 +1092,7 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
if (already_rewritten) {
stack.push_form_element(this, true);
return;
}
// first, let's try to detect if all bodies write the same value
std::optional<Variable> last_var;
@@ -1129,6 +1154,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
}
}
// process else.
FormStack temp_stack;
for (auto& elt : else_ir->elts()) {
elt->push_to_stack(env, pool, temp_stack);
@@ -1146,6 +1172,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
else_ir->push_back(e);
}
// raise expression.
auto top_condition = entries.front().condition;
if (!top_condition->is_single_element()) {
auto real_condition = top_condition->back();
@@ -1181,6 +1208,7 @@ void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStac
} else {
if (already_rewritten) {
stack.push_form_element(this, true);
return;
}
for (int i = 0; i < int(entries.size()); i++) {
auto& entry = entries.at(i);
@@ -1201,6 +1229,17 @@ void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStac
entry.condition->push_back(e);
}
}
auto top_condition = entries.front().condition;
if (!top_condition->is_single_element()) {
auto real_condition = top_condition->back();
top_condition->pop_back();
for (auto x : top_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
top_condition->elts() = {real_condition};
}
assert(used_as_value.has_value());
stack.push_value_to_reg(final_result, pool.alloc_single_form(nullptr, this), true);
already_rewritten = true;
@@ -1438,7 +1477,8 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack)
auto as_special = dynamic_cast<const SpecialOp*>(m_op);
if (as_special) {
if (as_special->kind() == SpecialOp::Kind::NOP) {
if (as_special->kind() == SpecialOp::Kind::NOP ||
as_special->kind() == SpecialOp::Kind::BREAK) {
stack.push_form_element(this, true);
return;
}
@@ -1687,4 +1727,20 @@ void ConditionalMoveFalseElement::push_to_stack(const Env&, FormPool&, FormStack
stack.push_form_element(this, true);
}
void SimpleAtomElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
void SimpleAtomElement::update_from_stack(const Env&,
FormPool&,
FormStack&,
std::vector<FormElement*>* result,
bool) {
result->push_back(this);
}
void SimpleExpressionElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
} // namespace decompiler
+1
View File
@@ -120,6 +120,7 @@ enum class FixedOperatorKind {
GEQ,
EQ,
NEQ,
CONS,
INVALID
};
+72 -14
View File
@@ -1204,6 +1204,76 @@ Form* merge_cond_else_with_sc_cond(FormPool& pool,
return result;
}
namespace {
template <typename T>
bool contains(const std::vector<T>& vec, const T& val) {
for (auto& x : vec) {
if (val == x) {
return true;
}
}
return false;
}
} // namespace
template <typename T>
void convert_and_inline(FormPool& pool, Function& f, const BlockVtx* as_block, T* output) {
auto start_op = f.ir2.atomic_ops->block_id_to_first_atomic_op.at(as_block->block_id);
auto end_op = f.ir2.atomic_ops->block_id_to_end_atomic_op.at(as_block->block_id);
std::vector<int> add_map;
for (auto i = start_op; i < end_op; i++) {
// convert to a form.
auto op = f.ir2.atomic_ops->ops.at(i)->get_as_form(pool, f.ir2.env);
bool add = true;
// check if we got a set, which we might want to eliminate
auto op_as_set = dynamic_cast<SetVarElement*>(op);
if (op_as_set) {
// check for deadness
if (op_as_set->is_dead_set()) {
// we want to eliminate, but we should we fix up the register info.
add = false;
auto consumed_expr =
dynamic_cast<SimpleExpressionElement*>(op_as_set->src()->try_as_single_element());
assert(consumed_expr);
auto& consumed = consumed_expr->expr().get_arg(0).var();
for (int j = i; j-- > start_op;) {
auto& ri = f.ir2.env.reg_use().op.at(j);
auto& ao = f.ir2.atomic_ops->ops.at(j);
if (contains(ao->write_regs(), consumed.reg())) {
ri.written_and_unused.insert(consumed.reg());
// fmt::print("GOT 3, making {} wau by {}\n", consumed.reg().to_charp(),
// ao->to_string(f.ir2.env));
// HACK - regenerate:
if (add_map.at(j - start_op) != -1) {
// fmt::print("regenerating {} to ", output->at(add_map.at(j -
// start_op))->to_string(f.ir2.env));
output->at(add_map.at(j - start_op)) =
f.ir2.atomic_ops->ops.at(j)->get_as_form(pool, f.ir2.env);
// fmt::print("{}\n", output->at(add_map.at(j -
// start_op))->to_string(f.ir2.env));
}
break;
}
if (contains(ao->read_regs(), consumed.reg())) {
// fmt::print("GOT 2, making {} consumed by {}\n", consumed.reg().to_charp(),
// ao->to_string(f.ir2.env));
ri.consumes.insert(consumed.reg());
break;
}
}
}
}
if (add) {
add_map.push_back(output->size());
output->push_back(op);
} else {
add_map.push_back(-1);
}
}
}
void insert_cfg_into_list(FormPool& pool,
Function& f,
const CfgVtx* vtx,
@@ -1216,12 +1286,7 @@ void insert_cfg_into_list(FormPool& pool,
insert_cfg_into_list(pool, f, x, output);
}
} else if (as_block) {
// inline the ops.
auto start_op = f.ir2.atomic_ops->block_id_to_first_atomic_op.at(as_block->block_id);
auto end_op = f.ir2.atomic_ops->block_id_to_end_atomic_op.at(as_block->block_id);
for (auto i = start_op; i < end_op; i++) {
output->push_back(f.ir2.atomic_ops->ops.at(i)->get_as_form(pool, f.ir2.env));
}
convert_and_inline(pool, f, as_block, output);
} else {
auto ir = cfg_to_ir(pool, f, vtx);
for (auto x : ir->elts()) {
@@ -1233,16 +1298,9 @@ void insert_cfg_into_list(FormPool& pool,
Form* cfg_to_ir(FormPool& pool, Function& f, const CfgVtx* vtx) {
if (dynamic_cast<const BlockVtx*>(vtx)) {
auto* bv = dynamic_cast<const BlockVtx*>(vtx);
Form* output = pool.alloc_empty_form();
auto start_op = f.ir2.atomic_ops->block_id_to_first_atomic_op.at(bv->block_id);
auto end_op = f.ir2.atomic_ops->block_id_to_end_atomic_op.at(bv->block_id);
for (auto i = start_op; i < end_op; i++) {
output->push_back(f.ir2.atomic_ops->ops.at(i)->get_as_form(pool, f.ir2.env));
}
convert_and_inline(pool, f, bv, output);
return output;
} else if (dynamic_cast<const SequenceVtx*>(vtx)) {
auto* sv = dynamic_cast<const SequenceVtx*>(vtx);
Form* output = pool.alloc_empty_form();
+4 -92
View File
@@ -7,70 +7,13 @@
namespace decompiler {
// TODO - remove all these and put them in the analysis methods instead.
void clean_up_ifs(Form* top_level_form, const Env&) {
/*void clean_up_ifs(Form* top_level_form, const Env&) {
bool changed = true;
while (changed) {
for (auto x : top_level_form->elts()) {
assert(x->parent_form == top_level_form);
}
changed = false;
top_level_form->apply([&](FormElement* elt) {
auto as_cne = dynamic_cast<CondNoElseElement*>(elt);
if (!as_cne) {
return;
}
auto top_condition = as_cne->entries.front().condition;
if (!top_condition->is_single_element() && elt->parent_form) {
auto real_condition = top_condition->back();
top_condition->pop_back();
auto& parent_vector = elt->parent_form->elts();
// find us in the parent vector
auto me = std::find_if(parent_vector.begin(), parent_vector.end(),
[&](FormElement* x) { return x == elt; });
assert(me != parent_vector.end());
// now insert the fake condition
for (auto& x : top_condition->elts()) {
x->parent_form = elt->parent_form;
}
parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end());
top_condition->elts() = {real_condition};
changed = true;
}
});
for (auto x : top_level_form->elts()) {
assert(x->parent_form == top_level_form);
}
top_level_form->apply([&](FormElement* elt) {
auto as_sc = dynamic_cast<ShortCircuitElement*>(elt);
if (!as_sc) {
return;
}
auto top_condition = as_sc->entries.front().condition;
if (!top_condition->is_single_element() && elt->parent_form) {
auto real_condition = top_condition->back();
top_condition->pop_back();
auto& parent_vector = elt->parent_form->elts();
// find us in the parent vector
auto me = std::find_if(parent_vector.begin(), parent_vector.end(),
[&](FormElement* x) { return x == elt; });
assert(me != parent_vector.end());
// now insert the fake condition
for (auto& x : top_condition->elts()) {
x->parent_form = elt->parent_form;
}
parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end());
top_condition->elts() = {real_condition};
changed = true;
}
});
for (auto x : top_level_form->elts()) {
assert(x->parent_form == top_level_form);
@@ -107,7 +50,7 @@ void clean_up_ifs(Form* top_level_form, const Env&) {
}
});
}
}
}*/
bool convert_to_expressions(Form* top_level_form,
FormPool& pool,
@@ -118,27 +61,6 @@ bool convert_to_expressions(Form* top_level_form,
// fmt::print("Before anything:\n{}\n",
// pretty_print::to_string(top_level_form->to_form(f.ir2.env)));
try {
// top_level_form->apply_form([&](Form* form) {
// if (form == top_level_form || !form->is_single_element()) {
// FormStack stack;
// for (auto& entry : form->elts()) {
// fmt::print("push {} to stack\n", entry->to_form(f.ir2.env).print());
// entry->push_to_stack(f.ir2.env, pool, stack);
// }
// std::vector<FormElement*> new_entries;
// if (form == top_level_form && f.type.last_arg() != TypeSpec("none")) {
// new_entries = stack.rewrite_to_get_reg(pool, Register(Reg::GPR, Reg::V0));
// } else {
// new_entries = stack.rewrite(pool);
// }
// assert(!new_entries.empty());
// form->clear();
// for (auto x : new_entries) {
// form->push_back(x);
// }
// }
// });
FormStack stack;
for (auto& entry : top_level_form->elts()) {
// fmt::print("push {} to stack\n", entry->to_form(f.ir2.env).print());
@@ -172,10 +94,10 @@ bool convert_to_expressions(Form* top_level_form,
assert(x->parent_form == top_level_form);
}
// fix up stuff
clean_up_ifs(top_level_form, f.ir2.env);
} catch (std::exception& e) {
std::string warning = fmt::format("Expression building failed: {}", e.what());
std::string warning =
fmt::format("Expression building failed in {}: {}", f.guessed_name.to_string(), e.what());
lg::warn(warning);
f.warnings.append(";; " + warning);
return false;
@@ -206,16 +128,6 @@ bool convert_to_expressions(Form* top_level_form,
}
}
// strip out coloring moves
for (auto it = top_level_form->elts().begin(); it != top_level_form->elts().end();) {
auto as_x = dynamic_cast<SetVarElement*>(*it);
if (as_x && as_x->is_eliminated_coloring_move()) {
it = top_level_form->elts().erase(it);
} else {
it++;
}
}
return true;
}
} // namespace decompiler
@@ -80,8 +80,9 @@
],
"(method 14 dead-pool)":[
[23, ["v1", "process"]], // bad visit order with #f?
[28, ["s4", "(pointer process-tree)"]] // bug in real game, see gkernel.gc
// bug in game!
[25, ["v1", "(pointer process-tree)"]],
[30, ["s4", "(pointer process-tree)"]]
],
"throw":[
+3 -1
View File
@@ -5,6 +5,7 @@
#include "common/log/log.h"
#include "config.h"
#include "common/util/FileUtil.h"
#include "common/versions.h"
int main(int argc, char** argv) {
using namespace decompiler;
@@ -13,12 +14,13 @@ int main(int argc, char** argv) {
lg::set_stdout_level(lg::level::info);
lg::set_flush_level(lg::level::info);
lg::initialize();
lg::info("GOAL Decompiler version {}\n", versions::DECOMPILER_VERSION);
file_util::init_crc();
init_opcode_info();
if (argc != 4) {
printf("Usage: jak_disassembler <config_file> <in_folder> <out_folder>\n");
printf("Usage: decompiler <config_file> <in_folder> <out_folder>\n");
return 1;
}
+9
View File
@@ -0,0 +1,9 @@
## Version 1
- Fixed bug where eliminated moves would appear in output in the first condition of a function as `(set! a a)`.
- Improved expression building immediately before the condition of `if`/`cond`
- Recognize `(new 'global 'pair <a> <b>)` as `(cons <a> <b>)`
- Remove useless `(set! <a> #f)`
- Remove useless `(set! <a> <b>)` and eliminate useless temporaries created by these.
- Remove useless `set!`s sometimes appearing around functions `(set! <a> (some-function ...))` when the result is unused, but moved into a different register.
- Recognize `(break!)` (GOAL breakpoint)
- Support `(new 'process ...)`
+1
View File
@@ -23,6 +23,7 @@ add_executable(goalc-test
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormExpressionBuild.cpp
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormExpressionBuildLong.cpp
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_InstructionParser.cpp
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_gkernel_decomp.cpp
${GOALC_TEST_FRAMEWORK_SOURCES}
${GOALC_TEST_CASES})
+2 -17
View File
@@ -187,7 +187,6 @@ TEST_F(FormRegressionTest, FormatString) {
std::string type = "(function bfloat bfloat)";
std::string expected =
"(begin\n"
" (set! a0-0 a0-0)\n"
" (set! t9-0 format)\n"
" (set! a0-1 '#t)\n"
" (set! a1-0 L343)\n"
@@ -381,7 +380,6 @@ TEST_F(FormRegressionTest, DynamicMethodAccess) {
// nothing.
" )\n"
" )\n"
" (set! v1-5 '#f)\n"
" (ret-value v0-0)\n"
" )";
test_no_expr(func, type, expected);
@@ -423,8 +421,6 @@ TEST_F(FormRegressionTest, SimpleLoopMergeCheck) {
" (set! a0-0 (cdr a0-0))\n" // should have merged
" (set! v1-0 (+ v1-0 1))\n" // also should have merged
" )\n"
" (set! v1-1 '#f)\n"
" (set! v1-2 '#f)\n"
" (set! v0-0 (car a0-0))\n"
" (ret-value v0-0)\n"
" )";
@@ -495,7 +491,6 @@ TEST_F(FormRegressionTest, And) {
" (set! v0-0 (+ v0-0 1))\n" // merged (and the result)
" (set! v1-1 (cdr v1-1))\n" // also merged.
" )\n"
" (set! v1-2 '#f)\n" // while's false, I think.
" )\n"
" )"
"(ret-value v0-0))\n";
@@ -558,8 +553,6 @@ TEST_F(FormRegressionTest, FunctionCall) {
std::string expected =
"(begin (if\n" // this if needs regrouping.
" (begin\n"
" (set! a0-0 a0-0)\n" // s5-0 is the thing to check
" (set! a1-0 a1-0)\n" // gp-0 is the list
" (while\n"
" (begin\n"
" (or\n"
@@ -576,7 +569,6 @@ TEST_F(FormRegressionTest, FunctionCall) {
" )\n"
" (set! a1-0 (cdr a1-0))\n" // get next (merged)
" )\n"
" (set! v1-2 '#f)\n" // while loop thing
" (set! v1-3 '())\n" //
" (!= a1-0 v1-3)\n" // IF CONDITION
" )\n"
@@ -692,9 +684,7 @@ TEST_F(FormRegressionTest, NestedAndOr) {
std::string type = "(function object (function object object object) object)";
std::string expected =
"(begin\n"
" (set! a0-0 a0-0)\n" // gp-0 = list
" (set! a1-0 a1-0)\n" // s5-0 = func
" (set! s4-0 -1)\n" // s4-0 = flag
" (set! s4-0 -1)\n" // s4-0 = flag
" (while\n"
" (nonzero? s4-0)\n" // there is stuff to do...
" (set! s4-0 0)\n" // flag = 0
@@ -744,14 +734,10 @@ TEST_F(FormRegressionTest, NestedAndOr) {
" (set! (car s3-0) s1-0)\n" // set iter's car to cadr
" (set! v1-4 (cdr s3-0))\n" // current cdr
" (set! (car v1-4) s2-0)\n" // set cadr
" (set! v1-5 s2-0)\n" // iteration thing?
" )\n"
" (set! s3-0 (cdr s3-0))\n" // increment!
" )\n"
" (set! v1-10 '#f)\n"
" (set! v1-11 '#f)\n"
" )\n"
" (set! v1-12 '#f)\n"
" (set! v0-1 a0-0)\n"
" (ret-value v0-1)\n"
" )";
@@ -795,7 +781,6 @@ TEST_F(FormRegressionTest, NewMethod) {
std::string expected =
"(begin (when\n"
" (begin\n"
" (set! a2-0 a2-0)\n" // gp-0 is size
" (set! v1-0 object)\n"
" (set! t9-0 (-> v1-0 methods-by-name new))\n" // object new
" (set! v1-1 a1-0)\n" // ?
@@ -847,7 +832,7 @@ TEST_F(FormRegressionTest, Recursive) {
std::string type = "(function int int)";
std::string expected =
"(begin (cond\n"
" ((begin (set! a0-0 a0-0) (set! v1-0 1) (= a0-0 v1-0)) (set! v0-0 1))\n" // base
" ((begin (set! v1-0 1) (= a0-0 v1-0)) (set! v0-0 1))\n" // base
" (else\n"
" (set! t9-0 fact)\n" // recurse!
" (set! a0-1 (+ a0-0 -1))\n"
+3 -4
View File
@@ -1276,7 +1276,7 @@ TEST_F(FormRegressionTest, ExprAppend) {
" (set! v1-1 arg0)\n"
" (while (!= (cdr v1-1) '()) (nop!) (nop!) (set! v1-1 (cdr v1-1)))\n"
" (set! a2-1 '#f)\n"
" (when (!= v1-1 '()) (set! (cdr v1-1) arg1) (set! v1-2 arg1))\n"
" (if (!= v1-1 '()) (set! (cdr v1-1) arg1))\n"
" arg0\n"
" )\n"
" )";
@@ -1471,7 +1471,7 @@ TEST_F(FormRegressionTest, ExprInsertCons) {
std::string expected =
"(begin\n"
" (set! a3-0 (delete-car! (car arg0) arg1))\n"
" (new 'global 'pair arg0 a3-0)\n"
" (cons arg0 a3-0)\n"
" )";
test_with_expr(func, type, expected, true, "");
}
@@ -1599,7 +1599,6 @@ TEST_F(FormRegressionTest, ExprSort) {
" (set! s4-0 (+ s4-0 1))\n"
" (set! (car s3-0) s1-0)\n"
" (set! (car (cdr s3-0)) s2-0)\n"
" (set! v1-5 s2-0)\n"
" )\n"
" (set! s3-0 (cdr s3-0))\n"
" )\n"
@@ -2103,7 +2102,7 @@ TEST_F(FormRegressionTest, ExprPrintl) {
std::string expected =
"(begin\n"
" (set! a0-1 arg0)\n"
" (set! v1-2 ((method-of-type (rtype-of a0-1) print) a0-1))\n"
" ((method-of-type (rtype-of a0-1) print) a0-1)\n"
" (format (quote #t) \"~%\")\n"
" arg0\n"
" )";
@@ -1974,16 +1974,10 @@ TEST_F(FormRegressionTest, ExprValid) {
"(begin\n"
" (set!\n"
" v1-1\n"
" (begin\n"
" (set! arg0 arg0)\n"
" (set! arg1 arg1)\n"
" (set! arg2 arg2)\n"
" (set! arg4 arg4)\n"
" (and\n"
" (>= (the-as uint arg0) (the-as uint __START-OF-TABLE__))\n"
" (< (the-as uint arg0) (the-as uint 134217728))\n"
" )\n"
" )\n"
" )\n"
" (cond\n"
" ((not arg1)\n"
@@ -1991,30 +1985,24 @@ TEST_F(FormRegressionTest, ExprValid) {
" ((nonzero? (logand (the-as int arg0) 3))\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-4\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object (misaligned)~%\"\n"
" arg0\n"
" arg2\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
" ((not v1-1)\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-6\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object (bad address)~%\"\n"
" arg0\n"
" arg2\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
@@ -2029,8 +2017,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" ((nonzero? (logand (the-as int arg0) 15))\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-8\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n"
@@ -2038,7 +2024,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
@@ -2052,8 +2037,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" )\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-13\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n"
@@ -2061,7 +2044,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
@@ -2073,8 +2055,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" ((!= (logand (the-as int arg0) 7) 2)\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-15\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n"
@@ -2082,15 +2062,12 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
" ((not v1-1)\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-17\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n"
@@ -2098,7 +2075,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
@@ -2111,8 +2087,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" (else\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-20\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n"
@@ -2120,7 +2094,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
@@ -2129,8 +2102,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" ((!= (logand (the-as int arg0) 7) 4)\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-22\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n"
@@ -2138,15 +2109,12 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
" ((not v1-1)\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-24\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n"
@@ -2154,15 +2122,12 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
" ((and (= arg1 type) (!= (rtype-of arg0) type))\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-31\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type "
@@ -2172,11 +2137,11 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg1\n"
" (rtype-of arg0)\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
" (else\n"
// todo - why isn't this compacted?
" (set!\n"
" v1-33\n"
" (and\n"
@@ -2188,8 +2153,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" (v1-33\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-37\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type "
@@ -2199,15 +2162,12 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg1\n"
" (rtype-of arg0)\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
" ((not (type-type? (rtype-of arg0) arg1))\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-41\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' "
@@ -2217,7 +2177,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg1\n"
" (rtype-of arg0)\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
@@ -2228,8 +2187,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" ((>= (the-as uint arg0) (the-as uint v1-44))\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-46\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol "
@@ -2238,7 +2195,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
@@ -2252,8 +2208,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" )\n"
" (if\n"
" arg2\n"
" (set!\n"
" v1-50\n"
" (format\n"
" arg4\n"
" \"ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol "
@@ -2262,7 +2216,6 @@ TEST_F(FormRegressionTest, ExprValid) {
" arg2\n"
" arg1\n"
" )\n"
" )\n"
" )\n"
" (quote #f)\n"
" )\n"
+108
View File
@@ -0,0 +1,108 @@
#include "gtest/gtest.h"
#include "FormRegressionTest.h"
using namespace decompiler;
TEST_F(FormRegressionTest, ExprMethod7Object) {
std::string func =
" sll r0, r0, 0\n"
" or v0, a0, r0\n"
" jr ra\n"
" daddu sp, sp, r0\n";
std::string type = "(function object int object)";
std::string expected = "arg0";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, ExprLoadPackage) {
std::string func =
" sll r0, r0, 0\n"
"L278:\n"
" daddiu sp, sp, -48\n"
" sd ra, 0(sp)\n"
" sq s5, 16(sp)\n"
" sq gp, 32(sp)\n"
" or gp, a0, r0\n"
" or s5, a1, r0\n"
" lw t9, nmember(s7)\n"
" or a0, gp, r0\n"
" lw a1, *kernel-packages*(s7)\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
" bne s7, v0, L279\n"
" or v0, s7, r0\n"
" lw t9, dgo-load(s7)\n"
" or a0, gp, r0\n"
" addiu a2, r0, 15\n"
" lui a3, 32\n"
" or a1, s5, r0\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
" lw v1, pair(s7)\n"
" lwu t9, 16(v1)\n"
" daddiu a0, s7, global\n"
" lw a1, pair(s7)\n"
" lw a3, *kernel-packages*(s7)\n"
" or a2, gp, r0\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
" sw v0, *kernel-packages*(s7)\n"
"L279:\n"
" ld ra, 0(sp)\n"
" lq gp, 32(sp)\n"
" lq s5, 16(sp)\n"
" jr ra\n"
" daddiu sp, sp, 48\n";
std::string type = "(function string kheap pair)";
std::string expected =
"(when\n"
" (not (nmember arg0 *kernel-packages*))\n"
" (dgo-load arg0 arg1 15 2097152)\n"
" (set! v0-1 (cons arg0 *kernel-packages*))\n"
" (set! *kernel-packages* v0-1)\n"
" v0-1\n"
" )";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, ExprUnloadPackage) {
std::string func =
" sll r0, r0, 0\n"
" daddiu sp, sp, -16\n"
" sd ra, 0(sp)\n"
" lw t9, nmember(s7)\n"
" lw a1, *kernel-packages*(s7)\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
" or v1, v0, r0\n"
" beq s7, v1, L277\n"
" or a0, s7, r0\n"
" lw t9, delete!(s7)\n"
" lw a0, -2(v1)\n"
" lw a1, *kernel-packages*(s7)\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
" sw v0, *kernel-packages*(s7)\n"
" or v1, v0, r0\n"
"L277:\n"
" lw v0, *kernel-packages*(s7)\n"
" ld ra, 0(sp)\n"
" jr ra\n"
" daddiu sp, sp, 16\n";
std::string type = "(function string pair)";
std::string expected =
"(begin\n"
" (set! v1-0 (nmember arg0 *kernel-packages*))\n"
" (if v1-0 (set! *kernel-packages* (delete! (car v1-0) *kernel-packages*)))\n"
" *kernel-packages*\n"
" )";
test_with_expr(func, type, expected, true);
}