mirror of
https://github.com/open-goal/jak-project
synced 2026-08-21 23:00:45 -04:00
remove useless sets (#252)
This commit is contained in:
+2
-5
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -120,6 +120,7 @@ enum class FixedOperatorKind {
|
||||
GEQ,
|
||||
EQ,
|
||||
NEQ,
|
||||
CONS,
|
||||
INVALID
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ...)`
|
||||
@@ -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})
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user