diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index 825784ad67..665d0aa9d7 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -148,6 +148,7 @@ class SimpleAtom { return m_int; } bool is_int() const { return m_kind == Kind::INTEGER_CONSTANT; }; + bool is_int(s64 integer) const { return is_int() && get_int() == integer; } bool is_sym_ptr() const { return m_kind == Kind::SYMBOL_PTR; }; bool is_sym_val() const { return m_kind == Kind::SYMBOL_VAL; }; bool is_empty_list() const { return m_kind == Kind::EMPTY_LIST; }; diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index e1377d860d..7a50200adc 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -1969,4 +1969,74 @@ void LetElement::set_body(Form* new_body) { m_body->parent_element = this; } +///////////////////////////// +// DoTimesElement +///////////////////////////// + +DoTimesElement::DoTimesElement(RegisterAccess var_init, + RegisterAccess var_check, + RegisterAccess var_inc, + Form* check_value, + Form* body) + : m_var_init(var_init), + m_var_check(var_check), + m_var_inc(var_inc), + m_check_value(check_value), + m_body(body) { + m_body->parent_element = this; + m_check_value->parent_element = this; + assert(m_var_inc.reg() == m_var_check.reg()); + assert(m_var_init.reg() == m_var_inc.reg()); +} + +goos::Object DoTimesElement::to_form_internal(const Env& env) const { + std::vector outer = { + pretty_print::to_symbol("dotimes"), + pretty_print::build_list(m_var_init.to_form(env), m_check_value->to_form(env))}; + m_body->inline_forms(outer, env); + return pretty_print::build_list(outer); +} + +void DoTimesElement::apply(const std::function& f) { + f(this); + m_check_value->apply(f); + m_body->apply(f); +} + +void DoTimesElement::apply_form(const std::function& f) { + m_check_value->apply_form(f); + m_body->apply_form(f); +} + +void DoTimesElement::collect_vars(RegAccessSet& vars, bool recursive) const { + vars.insert(m_var_init); + vars.insert(m_var_check); + vars.insert(m_var_inc); + if (recursive) { + m_body->collect_vars(vars, recursive); + m_check_value->collect_vars(vars, recursive); + } +} + +void DoTimesElement::get_modified_regs(RegSet& regs) const { + regs.insert(m_var_inc.reg()); + m_body->get_modified_regs(regs); + m_check_value->get_modified_regs(regs); +} + +std::optional form_as_atom(const Form* f) { + auto as_single = f->try_as_single_element(); + auto as_atom = dynamic_cast(as_single); + if (as_atom) { + return as_atom->atom(); + } + + auto as_se = dynamic_cast(as_single); + if (as_se && as_se->expr().is_identity()) { + return as_se->expr().get_arg(0); + } + + return {}; +} + } // namespace decompiler diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 92a20ea6a3..8ac544f285 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -1162,6 +1162,25 @@ class LetElement : public FormElement { bool m_star = false; }; +class DoTimesElement : public FormElement { + public: + DoTimesElement(RegisterAccess var_init, + RegisterAccess var_check, + RegisterAccess var_inc, + Form* check_value, + Form* body); + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(RegAccessSet& vars, bool recursive) const override; + void get_modified_regs(RegSet& regs) const override; + + private: + RegisterAccess m_var_init, m_var_check, m_var_inc; + Form* m_check_value = nullptr; + Form* m_body = nullptr; +}; + /*! * A Form is a wrapper around one or more FormElements. * This is done for two reasons: @@ -1306,4 +1325,6 @@ class FormPool { std::vector m_forms; std::vector m_elements; }; + +std::optional form_as_atom(const Form* f); } // namespace decompiler diff --git a/decompiler/IR2/GenericElementMatcher.cpp b/decompiler/IR2/GenericElementMatcher.cpp index aab8f56f6b..073cec67de 100644 --- a/decompiler/IR2/GenericElementMatcher.cpp +++ b/decompiler/IR2/GenericElementMatcher.cpp @@ -123,6 +123,13 @@ Matcher Matcher::set(const Matcher& dst, const Matcher& src) { return m; } +Matcher Matcher::while_loop(const Matcher& condition, const Matcher& body) { + Matcher m; + m.m_kind = Kind::WHILE_LOOP; + m.m_sub_matchers = {condition, body}; + return m; +} + bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out) const { switch (m_kind) { case Kind::ANY: @@ -432,6 +439,22 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out) const { return true; } break; + case Kind::WHILE_LOOP: { + auto as_while = dynamic_cast(input->try_as_single_element()); + if (!as_while) { + return false; + } + + if (!m_sub_matchers.at(0).do_match(as_while->condition, maps_out)) { + return false; + } + + if (!m_sub_matchers.at(1).do_match(as_while->body, maps_out)) { + return false; + } + return true; + } break; + default: assert(false); return false; diff --git a/decompiler/IR2/GenericElementMatcher.h b/decompiler/IR2/GenericElementMatcher.h index 21cb4af476..0c7152b33e 100644 --- a/decompiler/IR2/GenericElementMatcher.h +++ b/decompiler/IR2/GenericElementMatcher.h @@ -45,6 +45,7 @@ class Matcher { static Matcher if_with_else(const Matcher& condition, const Matcher& true_case, const Matcher& false_case); + static Matcher while_loop(const Matcher& condition, const Matcher& body); enum class Kind { ANY_REG, // matching any register @@ -62,6 +63,7 @@ class Matcher { ANY_LABEL, SYMBOL, IF_WITH_ELSE, + WHILE_LOOP, INVALID }; diff --git a/decompiler/analysis/insert_lets.cpp b/decompiler/analysis/insert_lets.cpp index e82e799057..08351cfd83 100644 --- a/decompiler/analysis/insert_lets.cpp +++ b/decompiler/analysis/insert_lets.cpp @@ -1,6 +1,7 @@ #include #include "insert_lets.h" +#include "decompiler/IR2/GenericElementMatcher.h" namespace decompiler { @@ -79,6 +80,101 @@ Form* lca_form(Form* a, Form* b, const Env& env) { // fmt::print("{}\n\n", result->to_string(env)); return result; } + +bool is_constant_int(const Form* f, int val) { + auto as_atom = form_as_atom(f); + return as_atom && as_atom->is_int(val); +} + +FormElement* rewrite_as_dotimes(LetElement* in, const Env& env, FormPool& pool) { + // dotimes OpenGOAL: + /* + (defmacro dotimes (var &rest body) + "Loop like for (int i = 0; i < end; i++)" + `(let ((,(first var) 0)) + (while (< ,(first var) ,(second var)) + ,@body + (+1! ,(first var)) + ) + ,@(cddr var) + ) + ) + */ + + // should have this anyway, but double check so we don't throw this away. + if (in->entries().size() != 1) { + return nullptr; + } + + // look for setting a var to zero. + auto ra = in->entries().at(0).dest; + auto var = env.get_variable_name(ra); + if (!is_constant_int(in->entries().at(0).src, 0)) { + return nullptr; + } + + // still have to check body for the increment and have to check that the lt operates on the right + // thing. + Matcher while_matcher = + Matcher::while_loop(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::LT), + {Matcher::any_reg(0), Matcher::any(1)}), + Matcher::any(2)); + + auto mr = match(while_matcher, in->body()); + if (!mr.matched) { + return nullptr; + } + + // check the lt operation: + auto lt_var = mr.maps.regs.at(0); + assert(lt_var); + if (env.get_variable_name(*lt_var) != var) { + return nullptr; // wrong variable checked + } + + // check the body + auto body = mr.maps.forms.at(2); + auto last_in_body = body->elts().back(); + + // kind hacky + Form fake_form; + fake_form.elts().push_back(last_in_body); + Matcher increment_matcher = + Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::ADDITION_IN_PLACE), + {Matcher::any_reg(0), Matcher::integer(1)}); + + auto int_mr = match(increment_matcher, &fake_form); + if (!int_mr.matched) { + return nullptr; + } + + auto inc_var = int_mr.maps.regs.at(0); + assert(inc_var); + if (env.get_variable_name(*inc_var) != var) { + return nullptr; // wrong variable incremented + } + + // success! here we commit to modifying this: + + // first, remove the increment + body->pop_back(); + + return pool.alloc_element(in->entries().at(0).dest, *lt_var, *inc_var, + mr.maps.forms.at(1), body); +} + +/*! + * Attempt to rewrite a let as another form. If it cannot be rewritten, this will return nullptr. + */ +FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool) { + auto as_dotimes = rewrite_as_dotimes(in, env, pool); + if (as_dotimes) { + return as_dotimes; + } + + // nothing matched. + return nullptr; +} } // namespace LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_level_form) { @@ -296,7 +392,19 @@ LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_l group.first->claim_all_children(); } - // Part 8: (todo) recognize loops and stuff. + // Part 8: recognize loop forms + top_level_form->apply_form([&](Form* f) { + for (auto& elt : f->elts()) { + auto as_let = dynamic_cast(elt); + if (as_let) { + auto rewritten = rewrite_let(as_let, env, pool); + if (rewritten) { + rewritten->parent_form = f; + elt = rewritten; + } + } + } + }); // Part 9: compact recursive lets: bool changed = true; diff --git a/test/decompiler/reference/gcommon_REF.gc b/test/decompiler/reference/gcommon_REF.gc index 7a29eb6be3..1be8947f74 100644 --- a/test/decompiler/reference/gcommon_REF.gc +++ b/test/decompiler/reference/gcommon_REF.gc @@ -255,10 +255,7 @@ ;; definition for function ref (defun ref ((lst object) (index int)) - (let - ((count 0)) - (while (< count index) (nop!) (nop!) (set! lst (cdr lst)) (+! count 1)) - ) + (dotimes (count index) (nop!) (nop!) (set! lst (cdr lst))) (car lst) ) @@ -901,15 +898,11 @@ (defun mem-copy! ((dst pointer) (src pointer) (size int)) (let ((result dst)) - (let - ((i 0)) - (while - (< i size) - (set! (-> (the-as (pointer int8) dst)) (-> (the-as (pointer uint8) src))) - (&+! dst 1) - (&+! src 1) - (+! i 1) - ) + (dotimes + (i size) + (set! (-> (the-as (pointer int8) dst)) (-> (the-as (pointer uint8) src))) + (&+! dst 1) + (&+! src 1) ) result ) @@ -961,15 +954,11 @@ (defun mem-set32! ((dst pointer) (size int) (value int)) (let ((result dst)) - (let - ((i 0)) - (while - (< i size) - (set! (-> (the-as (pointer int32) dst)) value) - (&+! dst 4) - (nop!) - (+! i 1) - ) + (dotimes + (i size) + (set! (-> (the-as (pointer int32) dst)) value) + (&+! dst 4) + (nop!) ) result ) @@ -979,21 +968,17 @@ (defun mem-or! ((dst pointer) (src pointer) (size int)) (let ((result dst)) - (let - ((i 0)) - (while - (< i size) - (set! - (-> (the-as (pointer int8) dst)) - (logior - (-> (the-as (pointer uint8) dst)) - (-> (the-as (pointer uint8) src)) - ) + (dotimes + (i size) + (set! + (-> (the-as (pointer int8) dst)) + (logior + (-> (the-as (pointer uint8) dst)) + (-> (the-as (pointer uint8) src)) ) - (&+! dst 1) - (&+! src 1) - (+! i 1) ) + (&+! dst 1) + (&+! src 1) ) result ) @@ -1029,20 +1014,16 @@ ;; definition (debug) for function mem-print (defun-debug mem-print ((data (pointer uint32)) (word-count int)) - (let - ((current-qword 0)) - (while - (< current-qword (sar word-count 2)) - (format - 0 - "~X: ~X ~X ~X ~X~%" - (&-> data (shl current-qword 2)) - (-> data (shl current-qword 2)) - (-> data (+ (shl current-qword 2) 1)) - (-> data (+ (shl current-qword 2) 2)) - (-> data (+ (shl current-qword 2) 3)) - ) - (+! current-qword 1) + (dotimes + (current-qword (sar word-count 2)) + (format + 0 + "~X: ~X ~X ~X ~X~%" + (&-> data (shl current-qword 2)) + (-> data (shl current-qword 2)) + (-> data (+ (shl current-qword 2) 1)) + (-> data (+ (shl current-qword 2) 2)) + (-> data (+ (shl current-qword 2) 3)) ) ) #f @@ -1053,14 +1034,10 @@ ;; definition for function print-tree-bitmask (defun print-tree-bitmask ((bits int) (count int)) - (let - ((i 0)) - (while - (< i count) - (if (zero? (logand bits 1)) (format #t " ") (format #t "| ")) - (set! bits (shr bits 1)) - (+! i 1) - ) + (dotimes + (i count) + (if (zero? (logand bits 1)) (format #t " ") (format #t "| ")) + (set! bits (shr bits 1)) ) #f ) diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp index 4a0da8109f..a643af2a22 100644 --- a/test/decompiler/test_FormExpressionBuild.cpp +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -650,13 +650,7 @@ TEST_F(FormRegressionTest, ExprRef) { std::string type = "(function object int object)"; std::string expected = - "(begin\n" - " (let\n" - " ((v1-0 0))\n" - " (while (< v1-0 arg1) (nop!) (nop!) (set! arg0 (cdr arg0)) (+! v1-0 1))\n" - " )\n" - " (car arg0)\n" - " )"; + "(begin (dotimes (v1-0 arg1) (nop!) (nop!) (set! arg0 (cdr arg0))) (car arg0))"; test_with_expr(func, type, expected, true, ""); } @@ -1862,15 +1856,11 @@ TEST_F(FormRegressionTest, ExprMemCopy) { std::string expected = "(let\n" " ((v0-0 arg0))\n" - " (let\n" - " ((v1-0 0))\n" - " (while\n" - " (< v1-0 arg2)\n" - " (set! (-> (the-as (pointer int8) arg0)) (-> (the-as (pointer uint8) arg1)))\n" - " (&+! arg0 1)\n" - " (&+! arg1 1)\n" - " (+! v1-0 1)\n" - " )\n" + " (dotimes\n" + " (v1-0 arg2)\n" + " (set! (-> (the-as (pointer int8) arg0)) (-> (the-as (pointer uint8) arg1)))\n" + " (&+! arg0 1)\n" + " (&+! arg1 1)\n" " )\n" " v0-0\n" " )"; @@ -1905,15 +1895,11 @@ TEST_F(FormRegressionTest, ExprMemSet32) { std::string expected = "(let\n" " ((v0-0 arg0))\n" - " (let\n" - " ((v1-0 0))\n" - " (while\n" - " (< v1-0 arg1)\n" - " (set! (-> (the-as (pointer int32) arg0)) arg2)\n" - " (&+! arg0 4)\n" - " (nop!)\n" - " (+! v1-0 1)\n" - " )\n" + " (dotimes\n" + " (v1-0 arg1)\n" + " (set! (-> (the-as (pointer int32) arg0)) arg2)\n" + " (&+! arg0 4)\n" + " (nop!)\n" " )\n" " v0-0\n" " )"; @@ -1951,21 +1937,17 @@ TEST_F(FormRegressionTest, ExprMemOr) { std::string expected = "(let\n" " ((v0-0 arg0))\n" - " (let\n" - " ((v1-0 0))\n" - " (while\n" - " (< v1-0 arg2)\n" - " (set!\n" - " (-> (the-as (pointer int8) arg0))\n" - " (logior\n" - " (-> (the-as (pointer uint8) arg0))\n" - " (-> (the-as (pointer uint8) arg1))\n" - " )\n" + " (dotimes\n" + " (v1-0 arg2)\n" + " (set!\n" + " (-> (the-as (pointer int8) arg0))\n" + " (logior\n" + " (-> (the-as (pointer uint8) arg0))\n" + " (-> (the-as (pointer uint8) arg1))\n" " )\n" - " (&+! arg0 1)\n" - " (&+! arg1 1)\n" - " (+! v1-0 1)\n" " )\n" + " (&+! arg0 1)\n" + " (&+! arg1 1)\n" " )\n" " v0-0\n" " )"; @@ -2171,14 +2153,10 @@ TEST_F(FormRegressionTest, ExprPrintTreeBitmask) { std::string expected = "(begin\n" - " (let\n" - " ((s4-0 0))\n" - " (while\n" - " (< s4-0 arg1)\n" - " (if (zero? (logand arg0 1)) (format #t \" \") (format #t \"| \"))\n" - " (set! arg0 (shr arg0 1))\n" - " (+! s4-0 1)\n" - " )\n" + " (dotimes\n" + " (s4-0 arg1)\n" + " (if (zero? (logand arg0 1)) (format #t \" \") (format #t \"| \"))\n" + " (set! arg0 (shr arg0 1))\n" " )\n" " #f\n" " )"; @@ -2494,15 +2472,13 @@ TEST_F(FormRegressionTest, StringLt) { " ((method-of-type string length) arg1)\n" " )\n" " )\n" - " (v1-4 0)\n" " )\n" - " (while\n" - " (< v1-4 s4-1)\n" + " (dotimes\n" + " (v1-4 s4-1)\n" " (cond\n" " ((< (-> arg0 data v1-4) (-> arg1 data v1-4)) (return #t))\n" " ((< (-> arg1 data v1-4) (-> arg0 data v1-4)) (return #f))\n" " )\n" - " (+! v1-4 1)\n" " )\n" " )\n" " #f\n" diff --git a/test/decompiler/test_FormExpressionBuildLong.cpp b/test/decompiler/test_FormExpressionBuildLong.cpp index 2be3e3c4a9..42870253ad 100644 --- a/test/decompiler/test_FormExpressionBuildLong.cpp +++ b/test/decompiler/test_FormExpressionBuildLong.cpp @@ -545,148 +545,107 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " ((v1-1 (-> arg0 content-type symbol)))\n" " (cond\n" " ((= v1-1 (quote int32))\n" - " (let\n" - " ((s5-0 0))\n" - " (while\n" - " (< s5-0 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-0) \"~D\" \" ~D\")\n" - " (-> (the-as (array int32) arg0) s5-0)\n" - " )\n" - " (+! s5-0 1)\n" + " (dotimes\n" + " (s5-0 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-0) \"~D\" \" ~D\")\n" + " (-> (the-as (array int32) arg0) s5-0)\n" " )\n" " )\n" " )\n" " ((= v1-1 (quote uint32))\n" - " (let\n" - " ((s5-1 0))\n" - " (while\n" - " (< s5-1 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-1) \"~D\" \" ~D\")\n" - " (-> (the-as (array uint32) arg0) s5-1)\n" - " )\n" - " (+! s5-1 1)\n" + " (dotimes\n" + " (s5-1 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-1) \"~D\" \" ~D\")\n" + " (-> (the-as (array uint32) arg0) s5-1)\n" " )\n" " )\n" " )\n" " ((= v1-1 (quote int64))\n" - " (let\n" - " ((s5-2 0))\n" - " (while\n" - " (< s5-2 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-2) \"~D\" \" ~D\")\n" - " (-> (the-as (array int64) arg0) s5-2)\n" - " )\n" - " (+! s5-2 1)\n" + " (dotimes\n" + " (s5-2 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-2) \"~D\" \" ~D\")\n" + " (-> (the-as (array int64) arg0) s5-2)\n" " )\n" " )\n" " )\n" " ((= v1-1 (quote uint64))\n" - " (let\n" - " ((s5-3 0))\n" - " (while\n" - " (< s5-3 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-3) \"#x~X\" \" #x~X\")\n" - " (-> (the-as (array uint64) arg0) s5-3)\n" - " )\n" - " (+! s5-3 1)\n" + " (dotimes\n" + " (s5-3 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-3) \"#x~X\" \" #x~X\")\n" + " (-> (the-as (array uint64) arg0) s5-3)\n" " )\n" " )\n" " )\n" " ((= v1-1 (quote int8))\n" - " (let\n" - " ((s5-4 0))\n" - " (while\n" - " (< s5-4 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-4) \"~D\" \" ~D\")\n" - " (-> (the-as (array int8) arg0) s5-4)\n" - " )\n" - " (+! s5-4 1)\n" + " (dotimes\n" + " (s5-4 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-4) \"~D\" \" ~D\")\n" + " (-> (the-as (array int8) arg0) s5-4)\n" " )\n" " )\n" " )\n" " ((= v1-1 (quote uint8))\n" - " (let\n" - " ((s5-5 0))\n" - " (while\n" - " (< s5-5 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-5) \"~D\" \" ~D\")\n" - " (-> (the-as (array uint8) arg0) s5-5)\n" - " )\n" - " (+! s5-5 1)\n" + " (dotimes\n" + " (s5-5 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-5) \"~D\" \" ~D\")\n" + " (-> (the-as (array uint8) arg0) s5-5)\n" " )\n" " )\n" " )\n" " ((= v1-1 (quote int16))\n" - " (let\n" - " ((s5-6 0))\n" - " (while\n" - " (< s5-6 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-6) \"~D\" \" ~D\")\n" - " (-> (the-as (array int16) arg0) s5-6)\n" - " )\n" - " (+! s5-6 1)\n" + " (dotimes\n" + " (s5-6 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-6) \"~D\" \" ~D\")\n" + " (-> (the-as (array int16) arg0) s5-6)\n" " )\n" " )\n" " )\n" " ((= v1-1 (quote uint16))\n" - " (let\n" - " ((s5-7 0))\n" - " (while\n" - " (< s5-7 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-7) \"~D\" \" ~D\")\n" - " (-> (the-as (array uint16) arg0) s5-7)\n" - " )\n" - " (+! s5-7 1)\n" + " (dotimes\n" + " (s5-7 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-7) \"~D\" \" ~D\")\n" + " (-> (the-as (array uint16) arg0) s5-7)\n" " )\n" " )\n" " )\n" " (else\n" " (cond\n" " ((or (= v1-1 (quote uint128)) (= v1-1 (quote int128)))\n" - " (let\n" - " ((s5-8 0))\n" - " (while\n" - " (< s5-8 (-> arg0 length))\n" + " (dotimes\n" + " (s5-8 (-> arg0 length))\n" + " (let\n" + " ((t9-10 format) (a0-21 #t) (a1-11 (if (zero? s5-8) \"#x~X\" \" #x~X\")))\n" " (let\n" - " ((t9-10 format) (a0-21 #t) (a1-11 (if (zero? s5-8) \"#x~X\" \" #x~X\")))\n" - " (let\n" - " ((v1-42 (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0))))\n" - " )\n" - " (.lq a2-8 12 v1-42)\n" - " )\n" - " (t9-10 a0-21 a1-11 a2-8)\n" + " ((v1-42 (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0)))))\n" + " (.lq a2-8 12 v1-42)\n" " )\n" - " (+! s5-8 1)\n" + " (t9-10 a0-21 a1-11 a2-8)\n" " )\n" " )\n" " )\n" " (else\n" - " (let\n" - " ((s5-9 0))\n" - " (while\n" - " (< s5-9 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-9) \"~D\" \" ~D\")\n" - " (-> (the-as (array int32) arg0) s5-9)\n" - " )\n" - " (+! s5-9 1)\n" + " (dotimes\n" + " (s5-9 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-9) \"~D\" \" ~D\")\n" + " (-> (the-as (array int32) arg0) s5-9)\n" " )\n" " )\n" " )\n" @@ -696,30 +655,22 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (cond\n" " ((= (-> arg0 content-type) float)\n" - " (let\n" - " ((s5-10 0))\n" - " (while\n" - " (< s5-10 (-> arg0 length))\n" - " (if\n" - " (zero? s5-10)\n" - " (format #t \"~f\" (-> (the-as (array float) arg0) s5-10))\n" - " (format #t \" ~f\" (-> (the-as (array float) arg0) s5-10))\n" - " )\n" - " (+! s5-10 1)\n" + " (dotimes\n" + " (s5-10 (-> arg0 length))\n" + " (if\n" + " (zero? s5-10)\n" + " (format #t \"~f\" (-> (the-as (array float) arg0) s5-10))\n" + " (format #t \" ~f\" (-> (the-as (array float) arg0) s5-10))\n" " )\n" " )\n" " )\n" " (else\n" - " (let\n" - " ((s5-11 0))\n" - " (while\n" - " (< s5-11 (-> arg0 length))\n" - " (if\n" - " (zero? s5-11)\n" - " (format #t \"~A\" (-> (the-as (array basic) arg0) s5-11))\n" - " (format #t \" ~A\" (-> (the-as (array basic) arg0) s5-11))\n" - " )\n" - " (+! s5-11 1)\n" + " (dotimes\n" + " (s5-11 (-> arg0 length))\n" + " (if\n" + " (zero? s5-11)\n" + " (format #t \"~A\" (-> (the-as (array basic) arg0) s5-11))\n" + " (format #t \" ~A\" (-> (the-as (array basic) arg0) s5-11))\n" " )\n" " )\n" " )\n" @@ -1222,118 +1173,72 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " ((v1-1 (-> arg0 content-type symbol)))\n" " (cond\n" " ((= v1-1 (quote int32))\n" - " (let\n" - " ((s5-0 0))\n" - " (while\n" - " (< s5-0 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-0 (-> (the-as (array int32) arg0) s5-0))\n" - " (+! s5-0 1)\n" - " )\n" + " (dotimes\n" + " (s5-0 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-0 (-> (the-as (array int32) arg0) s5-0))\n" " )\n" " )\n" " ((= v1-1 (quote uint32))\n" - " (let\n" - " ((s5-1 0))\n" - " (while\n" - " (< s5-1 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-1 (-> (the-as (array uint32) arg0) s5-1))\n" - " (+! s5-1 1)\n" - " )\n" + " (dotimes\n" + " (s5-1 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-1 (-> (the-as (array uint32) arg0) s5-1))\n" " )\n" " )\n" " ((= v1-1 (quote int64))\n" - " (let\n" - " ((s5-2 0))\n" - " (while\n" - " (< s5-2 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-2 (-> (the-as (array int64) arg0) s5-2))\n" - " (+! s5-2 1)\n" - " )\n" + " (dotimes\n" + " (s5-2 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-2 (-> (the-as (array int64) arg0) s5-2))\n" " )\n" " )\n" " ((= v1-1 (quote uint64))\n" - " (let\n" - " ((s5-3 0))\n" - " (while\n" - " (< s5-3 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] #x~X~%\"\n" - " s5-3\n" - " (-> (the-as (array uint64) arg0) s5-3)\n" - " )\n" - " (+! s5-3 1)\n" - " )\n" + " (dotimes\n" + " (s5-3 (-> arg0 length))\n" + " (format #t \"~T [~D] #x~X~%\" s5-3 (-> (the-as (array uint64) arg0) s5-3))\n" " )\n" " )\n" " ((= v1-1 (quote int8))\n" - " (let\n" - " ((s5-4 0))\n" - " (while\n" - " (< s5-4 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-4 (-> (the-as (array int8) arg0) s5-4))\n" - " (+! s5-4 1)\n" - " )\n" + " (dotimes\n" + " (s5-4 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-4 (-> (the-as (array int8) arg0) s5-4))\n" " )\n" " )\n" " ((= v1-1 (quote uint8))\n" - " (let\n" - " ((s5-5 0))\n" - " (while\n" - " (< s5-5 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-5 (-> (the-as (array int8) arg0) s5-5))\n" - " (+! s5-5 1)\n" - " )\n" + " (dotimes\n" + " (s5-5 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-5 (-> (the-as (array int8) arg0) s5-5))\n" " )\n" " )\n" " ((= v1-1 (quote int16))\n" - " (let\n" - " ((s5-6 0))\n" - " (while\n" - " (< s5-6 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-6 (-> (the-as (array int16) arg0) s5-6))\n" - " (+! s5-6 1)\n" - " )\n" + " (dotimes\n" + " (s5-6 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-6 (-> (the-as (array int16) arg0) s5-6))\n" " )\n" " )\n" " ((= v1-1 (quote uint16))\n" - " (let\n" - " ((s5-7 0))\n" - " (while\n" - " (< s5-7 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-7 (-> (the-as (array uint16) arg0) s5-7))\n" - " (+! s5-7 1)\n" - " )\n" + " (dotimes\n" + " (s5-7 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-7 (-> (the-as (array uint16) arg0) s5-7))\n" " )\n" " )\n" " (else\n" " (cond\n" " ((or (= v1-1 (quote int128)) (= v1-1 (quote uint128)))\n" - " (let\n" - " ((s5-8 0))\n" - " (while\n" - " (< s5-8 (-> arg0 length))\n" + " (dotimes\n" + " (s5-8 (-> arg0 length))\n" + " (let\n" + " ((t9-14 format) (a0-25 #t) (a1-15 \"~T [~D] #x~X~%\") (a2-13 s5-8))\n" " (let\n" - " ((t9-14 format) (a0-25 #t) (a1-15 \"~T [~D] #x~X~%\") (a2-13 s5-8))\n" - " (let\n" - " ((v1-42 (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0))))\n" - " )\n" - " (.lq a3-10 12 v1-42)\n" - " )\n" - " (t9-14 a0-25 a1-15 a2-13 a3-10)\n" + " ((v1-42 (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0)))))\n" + " (.lq a3-10 12 v1-42)\n" " )\n" - " (+! s5-8 1)\n" + " (t9-14 a0-25 a1-15 a2-13 a3-10)\n" " )\n" " )\n" " )\n" " (else\n" - " (let\n" - " ((s5-9 0))\n" - " (while\n" - " (< s5-9 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-9 (-> arg0 s5-9))\n" - " (+! s5-9 1)\n" - " )\n" + " (dotimes\n" + " (s5-9 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-9 (-> arg0 s5-9))\n" " )\n" " )\n" " )\n" @@ -1342,23 +1247,15 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (cond\n" " ((= (-> arg0 content-type) float)\n" - " (let\n" - " ((s5-10 0))\n" - " (while\n" - " (< s5-10 (-> arg0 length))\n" - " (format #t \"~T [~D] ~f~%\" s5-10 (-> (the-as (array float) arg0) s5-10))\n" - " (+! s5-10 1)\n" - " )\n" + " (dotimes\n" + " (s5-10 (-> arg0 length))\n" + " (format #t \"~T [~D] ~f~%\" s5-10 (-> (the-as (array float) arg0) s5-10))\n" " )\n" " )\n" " (else\n" - " (let\n" - " ((s5-11 0))\n" - " (while\n" - " (< s5-11 (-> arg0 length))\n" - " (format #t \"~T [~D] ~A~%\" s5-11 (-> (the-as (array basic) arg0) s5-11))\n" - " (+! s5-11 1)\n" - " )\n" + " (dotimes\n" + " (s5-11 (-> arg0 length))\n" + " (format #t \"~T [~D] ~A~%\" s5-11 (-> (the-as (array basic) arg0) s5-11))\n" " )\n" " )\n" " )\n" diff --git a/test/decompiler/test_gkernel_decomp.cpp b/test/decompiler/test_gkernel_decomp.cpp index bb1539477e..09c9f23900 100644 --- a/test/decompiler/test_gkernel_decomp.cpp +++ b/test/decompiler/test_gkernel_decomp.cpp @@ -932,20 +932,16 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPool) { " (set! (-> s3-0 child) #f)\n" " (set! (-> s3-0 self) s3-0)\n" " (set! (-> s3-0 ppointer) (&-> s3-0 self))\n" - " (let\n" - " ((s2-1 0))\n" - " (while\n" - " (< s2-1 arg2)\n" - " (let\n" - " ((s1-0 (-> s3-0 child))\n" - " (v1-5 ((method-of-type process new) arg0 process (quote dead) arg3))\n" - " )\n" - " (let ((a0-3 v1-5)) (set! (-> s3-0 child) (if a0-3 (-> a0-3 ppointer))))\n" - " (let ((a0-4 s3-0)) (set! (-> v1-5 parent) (if a0-4 (-> a0-4 ppointer))))\n" - " (set! (-> v1-5 pool) s3-0)\n" - " (set! (-> v1-5 brother) s1-0)\n" + " (dotimes\n" + " (s2-1 arg2)\n" + " (let\n" + " ((s1-0 (-> s3-0 child))\n" + " (v1-5 ((method-of-type process new) arg0 process (quote dead) arg3))\n" " )\n" - " (+! s2-1 1)\n" + " (let ((a0-3 v1-5)) (set! (-> s3-0 child) (if a0-3 (-> a0-3 ppointer))))\n" + " (let ((a0-4 s3-0)) (set! (-> v1-5 parent) (if a0-4 (-> a0-4 ppointer))))\n" + " (set! (-> v1-5 pool) s3-0)\n" + " (set! (-> v1-5 brother) s1-0)\n" " )\n" " )\n" " s3-0\n"