From 3ea8cbea6f2c50f0721884d2a58624a00ca34f98 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Wed, 27 Jan 2021 15:39:50 -0500 Subject: [PATCH] misc small improvements (#217) --- decompiler/IR2/Form.cpp | 64 +++- decompiler/IR2/Form.h | 8 + decompiler/IR2/FormExpressionAnalysis.cpp | 49 ++- decompiler/IR2/FormStack.cpp | 27 +- decompiler/IR2/FormStack.h | 4 +- decompiler/analysis/expression_build.cpp | 167 +++++++-- .../decompiler/test_FormBeforeExpressions.cpp | 20 +- test/decompiler/test_FormExpressionBuild.cpp | 342 +++++++++--------- 8 files changed, 441 insertions(+), 240 deletions(-) diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index 1aeb1a2d30..5e4a07e7f6 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -32,6 +32,10 @@ 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 { + return to_form(env); +} + /////////////////// // Form ////////////////// @@ -50,6 +54,26 @@ 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); + } else { + std::vector 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)); + } else { + forms.push_back(x->to_form(env)); + } + } + + return pretty_print::build_list(forms); + } +} + std::string Form::to_string(const Env& env) const { return to_form(env).print(); } @@ -310,6 +334,14 @@ goos::Object ConditionElement::to_form(const Env& env) const { } } +goos::Object ConditionElement::to_form_as_condition(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); + } +} + void ConditionElement::apply(const std::function& f) { f(this); } @@ -435,7 +467,7 @@ goos::Object CondWithElseElement::to_form(const Env& env) const { else_ir->is_single_element()) { std::vector list; list.push_back(pretty_print::to_symbol("if")); - list.push_back(entries.front().condition->to_form(env)); + list.push_back(entries.front().condition->to_form_as_condition(env)); list.push_back(entries.front().body->to_form(env)); list.push_back(else_ir->to_form(env)); return pretty_print::build_list(list); @@ -444,7 +476,7 @@ goos::Object CondWithElseElement::to_form(const Env& env) const { list.push_back(pretty_print::to_symbol("cond")); for (auto& e : entries) { std::vector entry; - entry.push_back(e.condition->to_form(env)); + entry.push_back(e.condition->to_form_as_condition(env)); e.body->inline_forms(entry, env); list.push_back(pretty_print::build_list(entry)); } @@ -511,7 +543,7 @@ void WhileElement::apply(const std::function& f) { goos::Object WhileElement::to_form(const Env& env) const { std::vector list; list.push_back(pretty_print::to_symbol("while")); - list.push_back(condition->to_form(env)); + list.push_back(condition->to_form_as_condition(env)); body->inline_forms(list, env); return pretty_print::build_list(list); } @@ -540,7 +572,7 @@ void UntilElement::apply(const std::function& f) { goos::Object UntilElement::to_form(const Env& env) const { std::vector list; list.push_back(pretty_print::to_symbol("until")); - list.push_back(condition->to_form(env)); + list.push_back(condition->to_form_as_condition(env)); body->inline_forms(list, env); return pretty_print::build_list(list); } @@ -596,7 +628,7 @@ goos::Object ShortCircuitElement::to_form(const Env& env) const { assert(false); } for (auto& x : entries) { - forms.push_back(x.condition->to_form(env)); + forms.push_back(x.condition->to_form_as_condition(env)); } return pretty_print::build_list(forms); } @@ -617,7 +649,7 @@ goos::Object CondNoElseElement::to_form(const Env& env) const { // print as an if statement if we can put the body in a single form. std::vector list; list.push_back(pretty_print::to_symbol("if")); - list.push_back(entries.front().condition->to_form(env)); + list.push_back(entries.front().condition->to_form_as_condition(env)); list.push_back(entries.front().body->to_form(env)); return pretty_print::build_list(list); } else if (entries.size() == 1) { @@ -626,7 +658,7 @@ goos::Object CondNoElseElement::to_form(const Env& env) const { // unless. std::vector list; list.push_back(pretty_print::to_symbol("when")); - list.push_back(entries.front().condition->to_form(env)); + list.push_back(entries.front().condition->to_form_as_condition(env)); entries.front().body->inline_forms(list, env); return pretty_print::build_list(list); } else { @@ -634,7 +666,7 @@ goos::Object CondNoElseElement::to_form(const Env& env) const { list.push_back(pretty_print::to_symbol("cond")); for (auto& e : entries) { std::vector entry; - entry.push_back(e.condition->to_form(env)); + entry.push_back(e.condition->to_form_as_condition(env)); entries.front().body->inline_forms(list, env); list.push_back(pretty_print::build_list(entry)); } @@ -924,12 +956,18 @@ GenericElement::GenericElement(GenericOperator op, std::vector forms) : m_head(op), m_elts(std::move(forms)) {} goos::Object GenericElement::to_form(const Env& env) const { - std::vector result; - result.push_back(m_head.to_form(env)); - for (auto x : m_elts) { - result.push_back(x->to_form(env)); + if (m_head.kind() == GenericOperator::Kind::CONDITION_OPERATOR && + m_head.condition_kind() == IR2_Condition::Kind::TRUTHY) { + assert(m_elts.size() == 1); + return m_elts.front()->to_form_as_condition(env); + } else { + std::vector result; + result.push_back(m_head.to_form(env)); + for (auto x : m_elts) { + result.push_back(x->to_form(env)); + } + return pretty_print::build_list(result); } - return pretty_print::build_list(result); } void GenericElement::apply(const std::function& f) { diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 97cf582636..4788a00bfb 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -22,6 +22,7 @@ class FormElement { 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; virtual ~FormElement() = default; virtual void apply(const std::function& f) = 0; virtual void apply_form(const std::function& f) = 0; @@ -249,6 +250,7 @@ class ConditionElement : public FormElement { std::optional src1, RegSet consumed); goos::Object to_form(const Env& env) const override; + goos::Object to_form_as_condition(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& f) override; void collect_vars(VariableSet& vars) const override; @@ -607,6 +609,11 @@ class GenericOperator { return m_fixed_kind; } + IR2_Condition::Kind condition_kind() const { + assert(m_kind == Kind::CONDITION_OPERATOR); + return m_condition_kind; + } + const Form* func() const { assert(m_kind == Kind::FUNCTION_EXPR); return m_function; @@ -785,6 +792,7 @@ class Form { void clear() { m_elements.clear(); } goos::Object to_form(const Env& env) const; + goos::Object to_form_as_condition(const Env& env) const; std::string to_string(const Env& env) const; void inline_forms(std::vector& forms, const Env& env) const; void apply(const std::function& f); diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 55e038145a..94827715ac 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -412,9 +412,10 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta if (m_src->is_single_element()) { auto src_as_se = dynamic_cast(m_src->back()); if (src_as_se) { + const auto& consumes = env.reg_use().op.at(m_dst.idx()).consumes; if (src_as_se->expr().kind() == SimpleExpression::Kind::IDENTITY && src_as_se->expr().get_arg(0).is_var()) { - stack.push_value_to_reg(m_dst, m_src, false); + stack.push_non_seq_reg_to_reg(m_dst, src_as_se->expr().get_arg(0).var(), m_src); return; } } @@ -616,6 +617,35 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& } void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + // first, let's try to detect if all bodies write the same value + std::optional last_var; + bool rewrite_as_set = true; + + // collect all forms which should write the output. + std::vector write_output_forms; + for (const auto& entry : entries) { + write_output_forms.push_back(entry.body); + } + write_output_forms.push_back(else_ir); + + // check all to see if they write the value. + for (auto form : write_output_forms) { + auto last_in_body = dynamic_cast(form->elts().back()); + if (last_in_body) { + if (last_var.has_value()) { + if (last_var->reg() != last_in_body->dst().reg()) { + rewrite_as_set = false; + break; + } + } + last_var = last_in_body->dst(); + } + } + + if (rewrite_as_set) { + assert(last_var.has_value()); + } + for (auto& entry : entries) { for (auto form : {entry.condition, entry.body}) { FormStack temp_stack; @@ -624,8 +654,8 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac } std::vector new_entries; - if (form == entry.body) { - new_entries = temp_stack.rewrite(pool); + if (form == entry.body && rewrite_as_set) { + new_entries = temp_stack.rewrite_to_get_var(pool, *last_var, env); } else { new_entries = temp_stack.rewrite(pool); } @@ -642,14 +672,23 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac elt->push_to_stack(env, pool, temp_stack); } - auto new_entries = temp_stack.rewrite(pool); + std::vector new_entries; + if (rewrite_as_set) { + new_entries = temp_stack.rewrite_to_get_var(pool, *last_var, env); + } else { + new_entries = temp_stack.rewrite(pool); + } else_ir->clear(); for (auto e : new_entries) { else_ir->push_back(e); } - stack.push_form_element(this, true); + if (rewrite_as_set) { + stack.push_value_to_reg(*last_var, pool.alloc_single_form(nullptr, this), true); + } else { + stack.push_form_element(this, true); + } } /////////////////// diff --git a/decompiler/IR2/FormStack.cpp b/decompiler/IR2/FormStack.cpp index 0e6977805f..edb6fdb7b1 100644 --- a/decompiler/IR2/FormStack.cpp +++ b/decompiler/IR2/FormStack.cpp @@ -5,11 +5,13 @@ namespace decompiler { std::string FormStack::StackEntry::print(const Env& env) const { if (destination.has_value()) { assert(source && !elt); - return fmt::format("d: {} s: {} | {} <- {}", active, sequence_point, - destination.value().reg().to_charp(), source->to_string(env)); + return fmt::format("d: {} s: {} | {} <- {} f: {}", active, sequence_point, + destination.value().reg().to_charp(), source->to_string(env), + non_seq_source.has_value()); } else { assert(elt && !source); - return fmt::format("d: {} s: {} | {}", active, sequence_point, elt->to_string(env)); + return fmt::format("d: {} s: {} | {} f: {}", active, sequence_point, elt->to_string(env), + non_seq_source.has_value()); } } @@ -31,6 +33,18 @@ void FormStack::push_value_to_reg(Variable var, Form* value, bool sequence_point m_stack.push_back(entry); } +void FormStack::push_non_seq_reg_to_reg(const Variable& dst, + const Variable& src, + Form* src_as_form) { + StackEntry entry; + entry.active = true; + entry.sequence_point = false; + entry.destination = dst; + entry.non_seq_source = src; + entry.source = src_as_form; + m_stack.push_back(entry); +} + bool FormStack::is_single_expression() { int count = 0; for (auto& e : m_stack) { @@ -56,6 +70,13 @@ Form* FormStack::pop_reg(Register reg) { if (entry.destination->reg() == reg) { entry.active = false; assert(entry.source); + if (entry.non_seq_source.has_value()) { + assert(entry.sequence_point == false); + auto result = pop_reg(entry.non_seq_source->reg()); + if (result) { + return result; + } + } return entry.source; } else { // we didn't match diff --git a/decompiler/IR2/FormStack.h b/decompiler/IR2/FormStack.h index 4e761472f4..aab82a1692 100644 --- a/decompiler/IR2/FormStack.h +++ b/decompiler/IR2/FormStack.h @@ -14,6 +14,7 @@ class FormStack { public: FormStack() = default; void push_value_to_reg(Variable var, Form* value, bool sequence_point); + void push_non_seq_reg_to_reg(const Variable& dst, const Variable& src, Form* src_as_form); void push_form_element(FormElement* elt, bool sequence_point); Form* pop_reg(const Variable& var); Form* pop_reg(Register reg); @@ -26,7 +27,8 @@ class FormStack { struct StackEntry { bool active = true; // should this appear in the output? std::optional destination; // what register we are setting (or nullopt if no dest.) - Form* source = nullptr; // the value we are setting the register to. + std::optional non_seq_source; // source variable, if we are setting var to var. + Form* source = nullptr; // the value we are setting the register to. FormElement* elt = nullptr; bool sequence_point = false; diff --git a/decompiler/analysis/expression_build.cpp b/decompiler/analysis/expression_build.cpp index 0bca8b9714..4ed4a02acf 100644 --- a/decompiler/analysis/expression_build.cpp +++ b/decompiler/analysis/expression_build.cpp @@ -5,52 +5,143 @@ #include "decompiler/util/DecompilerTypeSystem.h" namespace decompiler { + +void insert_extras_into_parent(Form* top_condition, Form* parent_form, FormElement* this_elt) { + auto real_condition = top_condition->back(); + top_condition->pop_back(); + + auto& parent_vector = parent_form->elts(); + // find us in the parent vector + auto me = std::find_if(parent_vector.begin(), parent_vector.end(), + [&](FormElement* x) { return x == this_elt; }); + assert(me != parent_vector.end()); + + // now insert the fake condition + parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); + top_condition->elts() = {real_condition}; +} + void clean_up_ifs(Form* top_level_form) { - top_level_form->apply([&](FormElement* elt) { - auto as_cne = dynamic_cast(elt); - if (!as_cne) { - return; - } + bool changed = true; + while (changed) { + changed = false; + top_level_form->apply([&](FormElement* elt) { + auto as_cne = dynamic_cast(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 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()); + 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 - parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); - top_condition->elts() = {real_condition}; - } - }); + // now insert the fake condition + parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); + top_condition->elts() = {real_condition}; + changed = true; + } + }); - top_level_form->apply([&](FormElement* elt) { - auto as_cwe = dynamic_cast(elt); - if (!as_cwe) { - return; - } + top_level_form->apply([&](FormElement* elt) { + auto as_cwe = dynamic_cast(elt); + if (!as_cwe) { + return; + } - auto top_condition = as_cwe->entries.front().condition; - if (!top_condition->is_single_element() && elt->parent_form) { - auto real_condition = top_condition->back(); - top_condition->pop_back(); + auto top_condition = as_cwe->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()); + 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 - parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); - top_condition->elts() = {real_condition}; - } - }); + // now insert the fake condition + parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); + top_condition->elts() = {real_condition}; + changed = true; + } + }); + + top_level_form->apply([&](FormElement* elt) { + auto as_sc = dynamic_cast(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 + parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); + top_condition->elts() = {real_condition}; + changed = true; + } + // if (!changed) { + // auto as_condition = + // dynamic_cast(top_condition->try_as_single_element()); if + // (as_condition) { + // if (as_condition->op().kind() == GenericOperator::Kind::CONDITION_OPERATOR) { + // if (as_condition->op().condition_kind() == IR2_Condition::Kind::TRUTHY) { + // auto to_repack = as_condition->elts().front(); + // if (!to_repack->try_as_single_element() && as_condition->parent_form) { + // changed = true; + // insert_extras_into_parent(to_repack, as_condition->parent_form, + // as_condition); + // } + // } + // } + // } + // } + }); + + top_level_form->apply([&](FormElement* elt) { + auto as_ge = dynamic_cast(elt); + if (!as_ge) { + return; + } + + if (as_ge->op().kind() == GenericOperator::Kind::CONDITION_OPERATOR) { + if (as_ge->op().condition_kind() == IR2_Condition::Kind::TRUTHY) { + assert(as_ge->elts().size() == 1); + auto top_condition = as_ge->elts().front(); + 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 + parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); + top_condition->elts() = {real_condition}; + changed = true; + } + } + } + }); + } } bool convert_to_expressions(Form* top_level_form, diff --git a/test/decompiler/test_FormBeforeExpressions.cpp b/test/decompiler/test_FormBeforeExpressions.cpp index 1b05fe3a34..6e5c85c8ba 100644 --- a/test/decompiler/test_FormBeforeExpressions.cpp +++ b/test/decompiler/test_FormBeforeExpressions.cpp @@ -291,12 +291,12 @@ TEST_F(FormRegressionTest, Or) { " (begin\n" " (set! a0-0 (-> a0-0 parent))\n" " (set! a3-0 (= a0-0 v1-0))\n" - " (truthy a3-0)\n" // this sets a2-0, the unused result of the OR. it gets a separate - // variable because it's not used. + " a3-0\n" // this sets a2-0, the unused result of the OR. it gets a separate + // variable because it's not used. " )\n" " (set! a2-1 (zero? a0-0))\n" // so this should be a2-1. " )\n" - " (truthy a2-1)\n" + " a2-1\n" " )\n" " (if\n" " (= a0-0 a1-0)\n" @@ -487,10 +487,10 @@ TEST_F(FormRegressionTest, And) { " (while\n" " (begin\n" " (and\n" - " (begin (set! a0-1 '()) (set! a1-0 (!= v1-1 a0-1)) (truthy a1-0))\n" // check v1-1 - " (begin (set! a0-3 (sll v1-1 62)) (set! a0-2 (<0.si a0-3)))\n" // check v1-1 + " (begin (set! a0-1 '()) (set! a1-0 (!= v1-1 a0-1)) a1-0)\n" // check v1-1 + " (begin (set! a0-3 (sll v1-1 62)) (set! a0-2 (<0.si a0-3)))\n" // check v1-1 " )\n" - " (truthy a0-2)\n" // this variable doesn't appear, but is set by the and. + " a0-2\n" // this variable doesn't appear, but is set by the and. " )\n" " (set! v0-0 (+ v0-0 1))\n" // merged (and the result) " (set! v1-1 (cdr v1-1))\n" // also merged. @@ -563,7 +563,7 @@ TEST_F(FormRegressionTest, FunctionCall) { " (while\n" " (begin\n" " (or\n" - " (begin (set! v1-0 '()) (set! a0-1 (= gp-0 v1-0)) (truthy a0-1))\n" // got empty list. + " (begin (set! v1-0 '()) (set! a0-1 (= gp-0 v1-0)) a0-1)\n" // got empty list. " (begin\n" " (set! t9-0 name=)\n" " (set! a0-2 (car gp-0))\n" @@ -706,7 +706,7 @@ TEST_F(FormRegressionTest, NestedAndOr) { " (set! v1-6 (cdr s3-0))\n" // s3-0 = cdr " (set! a0-4 '())\n" " (set! a0-5 (= v1-6 a0-4))\n" - " (truthy a0-5)\n" // cdr = empty list (sets v1-7 secretly) + " a0-5\n" // cdr = empty list (sets v1-7 secretly) " )\n" " (begin\n" " (set! v1-8 (cdr s3-0))\n" @@ -734,11 +734,11 @@ TEST_F(FormRegressionTest, NestedAndOr) { " )\n" " (set! a0-2 (>0.si v1-1))\n" // >0 " )\n" - " (truthy a0-2)\n" // false or >0 + " a0-2\n" // false or >0 " )\n" " (begin (set! a0-3 '#t) (set! v1-2 (!= v1-2 a0-3)))\n" // not #t " )\n" - " (truthy v1-2)\n" // (and (or false >0) (not #t)) + " v1-2\n" // (and (or false >0) (not #t)) " )\n" " (set! s4-0 (+ s4-0 1))\n" // increment, merge " (set! (car s3-0) s1-0)\n" // set iter's car to cadr diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp index 59ef0595e9..6fff82ec51 100644 --- a/test/decompiler/test_FormExpressionBuild.cpp +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -513,11 +513,9 @@ TEST_F(FormRegressionTest, ExprTypeTypep) { "(begin\n" " (set! v1-0 object)\n" " (until\n" - " (truthy\n" - " (or\n" - " (begin (set! a0-0 (-> a0-0 parent)) (truthy (= a0-0 v1-0)))\n" // set! as value. - " (zero? a0-0)\n" - " )\n" + " (begin\n" + " (set! a0-0 (-> a0-0 parent))\n" + " (or (= a0-0 v1-0) (zero? a0-0))\n" " )\n" " (if (= a0-0 a1-0) (return '#t (set! v1-0 0)))\n" " )\n" @@ -686,9 +684,8 @@ TEST_F(FormRegressionTest, ExprPairMethod4) { " (set! v1-1 (cdr a0-0))\n" " (set! v0-0 1)\n" " (while\n" - " (truthy\n" - " (and (truthy (!= v1-1 '())) " - " (<0.si (sll (the-as uint v1-1) 62)))\n" + " (and (!= v1-1 '()) " + " (<0.si (sll (the-as uint v1-1) 62))\n" " )\n" " (set! v0-0 (+ v0-0 1))\n" " (set! v1-1 (cdr v1-1))\n" @@ -795,7 +792,7 @@ TEST_F(FormRegressionTest, ExprMember) { "(begin\n" " (set! v1-0 a1-0)\n" " (while\n" - " (not (or (truthy (= v1-0 '())) (= (car v1-0) a0-0)))\n" + " (not (or (= v1-0 '()) (= (car v1-0) a0-0)))\n" " (set! v1-0 (cdr v1-0))\n" " )\n" " (set! a0-1 '#f)\n" @@ -860,7 +857,7 @@ TEST_F(FormRegressionTest, ExprNmember) { " (set! s5-0 a0-0)\n" " (set! gp-0 a1-0)\n" " (while\n" - " (not (or (truthy (= gp-0 '())) (name= (car gp-0) s5-0)))\n" + " (not (or (= gp-0 '()) (name= (car gp-0) s5-0)))\n" " (set! gp-0 (cdr gp-0))\n" " )\n" " (set! v1-2 '#f)\n" @@ -912,7 +909,7 @@ TEST_F(FormRegressionTest, ExprAssoc) { "(begin\n" " (set! v1-0 a1-0)\n" " (while\n" - " (not (or (truthy (= v1-0 '())) (= (car (car v1-0)) a0-0)))\n" + " (not (or (= v1-0 '()) (= (car (car v1-0)) a0-0)))\n" " (set! v1-0 (cdr v1-0))\n" " )\n" " (set! a0-1 '#f)\n" @@ -977,8 +974,8 @@ TEST_F(FormRegressionTest, ExprAssoce) { " (while\n" " (not\n" " (or\n" - " (truthy (= v1-0 '()))\n" - " (truthy (= (car (car v1-0)) a0-0))\n" + " (= v1-0 '())\n" + " (= (car (car v1-0)) a0-0)\n" " (= (car (car v1-0)) 'else)\n" " )\n" " )\n" @@ -1058,7 +1055,6 @@ TEST_F(FormRegressionTest, ExprNassoc) { " daddiu sp, sp, 48"; std::string type = "(function object object object)"; - // will need fixing if we clean up the set! if thing std::string expected = "(begin\n" " (set! s5-0 a0-0)\n" @@ -1066,22 +1062,17 @@ TEST_F(FormRegressionTest, ExprNassoc) { " (while\n" " (not\n" " (or\n" - " (truthy (= gp-0 '()))\n" + " (= gp-0 (quote ()))\n" " (begin\n" " (set! a1-1 (car (car gp-0)))\n" - " (if\n" - " (pair? a1-1)\n" - " (set! v1-1 (nmember s5-0 a1-1))\n" - " (set! v1-1 (name= a1-1 s5-0))\n" - " )\n" - " v1-1\n" + " (if (pair? a1-1) (nmember s5-0 a1-1) (name= a1-1 s5-0))\n" " )\n" " )\n" " )\n" " (set! gp-0 (cdr gp-0))\n" " )\n" - " (set! v1-3 '#f)\n" - " (if (!= gp-0 '()) (car gp-0))\n" + " (set! v1-3 (quote #f))\n" + " (if (!= gp-0 (quote ())) (car gp-0))\n" " )"; test_with_expr(func, type, expected, true, ""); } @@ -1172,22 +1163,21 @@ TEST_F(FormRegressionTest, ExprNassoce) { " (while\n" " (not\n" " (or\n" - " (truthy (= gp-0 '()))\n" + " (= gp-0 (quote ()))\n" " (begin\n" " (set! s4-0 (car (car gp-0)))\n" " (if\n" " (pair? s4-0)\n" - " (set! v1-1 (nmember s5-0 s4-0))\n" - " (set! v1-1 (or (truthy (name= s4-0 s5-0)) (= s4-0 'else)))\n" + " (nmember s5-0 s4-0)\n" + " (or (name= s4-0 s5-0) (= s4-0 (quote else)))\n" " )\n" - " v1-1\n" " )\n" " )\n" " )\n" " (set! gp-0 (cdr gp-0))\n" " )\n" - " (set! v1-4 '#f)\n" - " (if (!= gp-0 '()) (car gp-0))\n" + " (set! v1-4 (quote #f))\n" + " (if (!= gp-0 (quote ())) (car gp-0))\n" " )"; test_with_expr(func, type, expected, true, ""); } @@ -1236,25 +1226,16 @@ TEST_F(FormRegressionTest, ExprAppend) { " daddu sp, sp, r0"; std::string type = "(function object object object)"; - // todo - will be changed by if fix. std::string expected = - "(begin\n" - " (cond\n" - " ((= a0-0 '()) (set! v0-0 a1-0))\n" - " (else\n" - " (set! v1-1 a0-0)\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) a1-0) " - " (set! v1-2 a1-0))\n" - " (set! v0-0 a0-0)\n" - " )\n" + "(cond\n" + " ((= a0-0 '()) a1-0)\n" + " (else\n" + " (set! v1-1 a0-0)\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) a1-0) (set! v1-2 a1-0))\n" + " a0-0\n" " )\n" - " v0-0\n" " )"; test_with_expr(func, type, expected, true, ""); } @@ -1314,25 +1295,24 @@ TEST_F(FormRegressionTest, ExprDelete) { " daddu sp, sp, r0"; std::string type = "(function object object pair)"; - // todo - will be changed by if fix. std::string expected = - "(begin\n" + "(the-as\n" + " pair\n" " (cond\n" - " ((= a0-0 (car a1-0)) (set! v0-0 (cdr a1-0)))\n" + " ((= a0-0 (car a1-0)) (cdr a1-0))\n" " (else\n" " (set! v1-1 a1-0)\n" " (set! a2-0 (cdr a1-0))\n" " (while\n" - " (not (or (truthy (= a2-0 (quote ()))) (= (car a2-0) a0-0)))\n" + " (not (or (= a2-0 (quote ())) (= (car a2-0) a0-0)))\n" " (set! v1-1 a2-0)\n" " (set! a2-0 (cdr a2-0))\n" " )\n" " (set! a0-1 (quote #f))\n" " (if (!= a2-0 (quote ())) (set! (cdr v1-1) (cdr a2-0)))\n" - " (set! v0-0 a1-0)\n" + " a1-0\n" " )\n" " )\n" - " (the-as pair v0-0)\n" " )"; test_with_expr(func, type, expected, true, ""); } @@ -1394,25 +1374,24 @@ TEST_F(FormRegressionTest, ExprDeleteCar) { " daddu sp, sp, r0"; std::string type = "(function object object pair)"; - // todo - will be changed by if fix. std::string expected = - "(begin\n" + "(the-as\n" + " pair\n" " (cond\n" - " ((= a0-0 (car (car a1-0))) (set! v0-0 (cdr a1-0)))\n" + " ((= a0-0 (car (car a1-0))) (cdr a1-0))\n" " (else\n" " (set! v1-2 a1-0)\n" " (set! a2-0 (cdr a1-0))\n" " (while\n" - " (not (or (truthy (= a2-0 (quote ()))) (= (car (car a2-0)) a0-0)))\n" + " (not (or (= a2-0 (quote ())) (= (car (car a2-0)) a0-0)))\n" " (set! v1-2 a2-0)\n" " (set! a2-0 (cdr a2-0))\n" " )\n" " (set! a0-1 (quote #f))\n" " (if (!= a2-0 (quote ())) (set! (cdr v1-2) (cdr a2-0)))\n" - " (set! v0-0 a1-0)\n" + " a1-0\n" " )\n" " )\n" - " (the-as pair v0-0)\n" " )"; test_with_expr(func, type, expected, true, ""); } @@ -1455,115 +1434,138 @@ TEST_F(FormRegressionTest, ExprInsertCons) { test_with_expr(func, type, expected, true, ""); } -// TEST_F(FormRegressionTest, ExprSort) { -// std::string func = -// " sll r0, r0, 0\n" -// " daddiu sp, sp, -112\n" -// " sd ra, 0(sp)\n" -// " sq s1, 16(sp)\n" -// " sq s2, 32(sp)\n" -// " sq s3, 48(sp)\n" -// " sq s4, 64(sp)\n" -// " sq s5, 80(sp)\n" -// " sq gp, 96(sp)\n" -// -// " or gp, a0, r0\n" -// " or s5, a1, r0\n" -// " addiu s4, r0, -1\n" -// " beq r0, r0, L208\n" -// " sll r0, r0, 0\n" -// -// "L201:\n" -// " addiu s4, r0, 0\n" -// " or s3, gp, r0\n" -// " beq r0, r0, L206\n" -// " sll r0, r0, 0\n" -// -// "L202:\n" -// " lw s2, -2(s3)\n" -// " lw v1, 2(s3)\n" -// " lw s1, -2(v1)\n" -// " or t9, s5, r0\n" -// " or a0, s2, r0\n" -// " or a1, s1, r0\n" -// " jalr ra, t9\n" -// " sll v0, ra, 0\n" -// -// " or v1, v0, r0\n" -// " beql s7, v1, L203\n" -// " daddiu a0, s7, 8\n" -// -// " slt a1, r0, v1\n" -// " daddiu a0, s7, 8\n" -// " movz a0, s7, a1\n" -// -// "L203:\n" -// " beql s7, a0, L204\n" -// " or v1, a0, r0\n" -// -// " daddiu a0, s7, #t\n" -// " dsubu a0, v1, a0\n" -// " daddiu v1, s7, 8\n" -// " movz v1, s7, a0\n" -// -// "L204:\n" -// " beq s7, v1, L205\n" -// " or v1, s7, r0\n" -// -// " daddiu s4, s4, 1\n" -// " sw s1, -2(s3)\n" -// " lw v1, 2(s3)\n" -// " sw s2, -2(v1)\n" -// " or v1, s2, r0\n" -// -// "L205:\n" -// " lw s3, 2(s3)\n" -// -// "L206:\n" -// " lw v1, 2(s3)\n" -// " daddiu a0, s7, -10\n" -// " dsubu v1, v1, a0\n" -// " daddiu a0, s7, 8\n" -// " movn a0, s7, v1\n" -// " bnel s7, a0, L207\n" -// " or v1, a0, r0\n" -// -// " lw v1, 2(s3)\n" -// " dsll32 v1, v1, 30\n" -// " slt a0, v1, r0\n" -// " daddiu v1, s7, 8\n" -// " movn v1, s7, a0\n" -// -// "L207:\n" -// " beq s7, v1, L202\n" -// " sll r0, r0, 0\n" -// -// " or v1, s7, r0\n" -// " or v1, s7, r0\n" -// -// "L208:\n" -// " bne s4, r0, L201\n" -// " sll r0, r0, 0\n" -// -// " or v1, s7, r0\n" -// " or v0, gp, r0\n" -// " ld ra, 0(sp)\n" -// " lq gp, 96(sp)\n" -// " lq s5, 80(sp)\n" -// " lq s4, 64(sp)\n" -// " lq s3, 48(sp)\n" -// " lq s2, 32(sp)\n" -// " lq s1, 16(sp)\n" -// " jr ra\n" -// " daddiu sp, sp, 112"; -// std::string type = "(function object (function object object object) object)"; -// -// // NOTE - this appears to _not_ be a nested call. -// std::string expected = -// "(begin\n" -// " (set! gp-0 a0-0)\n" -// " (set! a3-0 (delete-car! (car gp-0) a1-0))\n" -// " (new 'global pair gp-0 a3-0)\n" -// " )"; -// test_with_expr(func, type, expected, true, ""); -//} \ No newline at end of file +TEST_F(FormRegressionTest, ExprSort) { + std::string func = + " sll r0, r0, 0\n" + " daddiu sp, sp, -112\n" + " sd ra, 0(sp)\n" + " sq s1, 16(sp)\n" + " sq s2, 32(sp)\n" + " sq s3, 48(sp)\n" + " sq s4, 64(sp)\n" + " sq s5, 80(sp)\n" + " sq gp, 96(sp)\n" + + " or gp, a0, r0\n" + " or s5, a1, r0\n" + " addiu s4, r0, -1\n" + " beq r0, r0, L208\n" + " sll r0, r0, 0\n" + + "L201:\n" + " addiu s4, r0, 0\n" + " or s3, gp, r0\n" + " beq r0, r0, L206\n" + " sll r0, r0, 0\n" + + "L202:\n" + " lw s2, -2(s3)\n" + " lw v1, 2(s3)\n" + " lw s1, -2(v1)\n" + " or t9, s5, r0\n" + " or a0, s2, r0\n" + " or a1, s1, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + " beql s7, v1, L203\n" + " daddiu a0, s7, 8\n" + + " slt a1, r0, v1\n" + " daddiu a0, s7, 8\n" + " movz a0, s7, a1\n" + + "L203:\n" + " beql s7, a0, L204\n" + " or v1, a0, r0\n" + + " daddiu a0, s7, #t\n" + " dsubu a0, v1, a0\n" + " daddiu v1, s7, 8\n" + " movz v1, s7, a0\n" + + "L204:\n" + " beq s7, v1, L205\n" + " or v1, s7, r0\n" + + " daddiu s4, s4, 1\n" + " sw s1, -2(s3)\n" + " lw v1, 2(s3)\n" + " sw s2, -2(v1)\n" + " or v1, s2, r0\n" + + "L205:\n" + " lw s3, 2(s3)\n" + + "L206:\n" + " lw v1, 2(s3)\n" + " daddiu a0, s7, -10\n" + " dsubu v1, v1, a0\n" + " daddiu a0, s7, 8\n" + " movn a0, s7, v1\n" + " bnel s7, a0, L207\n" + " or v1, a0, r0\n" + + " lw v1, 2(s3)\n" + " dsll32 v1, v1, 30\n" + " slt a0, v1, r0\n" + " daddiu v1, s7, 8\n" + " movn v1, s7, a0\n" + + "L207:\n" + " beq s7, v1, L202\n" + " sll r0, r0, 0\n" + + " or v1, s7, r0\n" + " or v1, s7, r0\n" + + "L208:\n" + " bne s4, r0, L201\n" + " sll r0, r0, 0\n" + + " or v1, s7, r0\n" + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " lq gp, 96(sp)\n" + " lq s5, 80(sp)\n" + " lq s4, 64(sp)\n" + " lq s3, 48(sp)\n" + " lq s2, 32(sp)\n" + " lq s1, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 112"; + std::string type = "(function object (function object object object) object)"; + + // TODO - this should probably be tested. + std::string expected = + "(begin\n" + " (set! gp-0 a0-0)\n" + " (set! s5-0 a1-0)\n" + " (set! s4-0 -1)\n" + " (while\n" + " (nonzero? s4-0)\n" + " (set! s4-0 0)\n" + " (set! s3-0 gp-0)\n" + " (while\n" + " (not\n" + " (or (= (cdr s3-0) (quote ())) (>=0.si (sll (the-as uint (cdr s3-0)) 62)))\n" + " )\n" + " (set! v1-1 (s5-0 (car s3-0) (car (cdr s3-0))))\n" + " (when\n" + " (and (or (not v1-1) (>0.si v1-1)) (!= v1-2 (quote #t)))\n" + " (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" + " (set! v1-10 (quote #f))\n" + " (set! v1-11 (quote #f))\n" + " )\n" + " (set! v1-12 (quote #f))\n" + " gp-0\n" + " )"; + test_with_expr(func, type, expected, true, ""); +} \ No newline at end of file