[Decompiler] Fix up pretty printing and other small changes (#311)

* fix up pretty printing

* wip

* fix pointer cast signed vs unsigned issue
This commit is contained in:
water111
2021-03-06 20:16:48 -05:00
committed by GitHub
parent 0bf189f582
commit d8a82eeca1
16 changed files with 745 additions and 454 deletions
+2 -1
View File
@@ -38,6 +38,7 @@
*
*/
#include <cinttypes>
#include "Object.h"
#include "common/util/FileUtil.h"
#include "third-party/fmt/core.h"
@@ -92,7 +93,7 @@ std::string fixed_to_string(FloatType x) {
// it's an integer number, so let's just get this over with asap
if (exact_int) {
sprintf(buff, "%lld.0", rounded);
sprintf(buff, "%" PRId64 ".0", rounded);
return {buff};
} else {
// not an integer - see how many decimal cases we need
+74 -2
View File
@@ -289,7 +289,7 @@ static PrettyPrinterNode* propagatePretty(NodePool& pool,
for (auto* n = list; n; n = n->next) {
if (n->is_line_separator) {
previous_line_sep = true;
offset = indentStack.back() += n->specialIndentDelta;
offset = indentStack.back() + n->specialIndentDelta;
} else {
if (previous_line_sep) {
line_start = n;
@@ -483,6 +483,12 @@ void breakList(NodePool& pool, PrettyPrinterNode* leftParen, PrettyPrinterNode*
}
}
namespace {
const std::unordered_set<std::string> control_flow_start_forms = {
"while", "dotimes", "until", "if", "when",
};
}
void insertSpecialBreaks(NodePool& pool, PrettyPrinterNode* node) {
for (; node; node = node->next) {
if (!node->is_line_separator && node->tok->kind == FormToken::TokenKind::STRING) {
@@ -494,12 +500,78 @@ void insertSpecialBreaks(NodePool& pool, PrettyPrinterNode* node) {
}
}
if (name == "defun" || name == "defmethod" || name == "defun-debug") {
if (name == "defun" || name == "defmethod" || name == "defun-debug" || name == "let" ||
name == "let*") {
auto* parent_type_dec = getNextListOnLine(node);
if (parent_type_dec) {
insertNewlineAfter(pool, parent_type_dec->paren, 0);
breakList(pool, node->paren, parent_type_dec);
}
if ((name == "let" || name == "let*") && parent_type_dec) {
if (parent_type_dec->tok->kind == FormToken::TokenKind::OPEN_PAREN) {
breakList(pool, parent_type_dec);
}
auto open_paren = node->prev;
if (open_paren && open_paren->tok->kind == FormToken::TokenKind::OPEN_PAREN) {
// insertNewlineBefore(pool, open_paren, 0);
if (open_paren->prev) {
breakList(pool, open_paren->prev->paren, open_paren);
}
}
}
}
if (control_flow_start_forms.find(name) != control_flow_start_forms.end()) {
auto* parent_type_dec = getNextListOnLine(node);
if (parent_type_dec) {
insertNewlineAfter(pool, parent_type_dec->paren, 0);
breakList(pool, node->paren, parent_type_dec);
auto open_paren = node->prev;
if (open_paren && open_paren->tok->kind == FormToken::TokenKind::OPEN_PAREN) {
if (open_paren->prev && !open_paren->prev->is_line_separator) {
if (open_paren->prev) {
auto to_break = open_paren->prev->paren;
if (to_break->tok && to_break->tok->kind == FormToken::TokenKind::OPEN_PAREN) {
breakList(pool, open_paren->prev->paren, open_paren);
}
}
}
}
}
}
if (name == "cond") {
auto* start_of_case = getNextListOnLine(node);
while (true) {
// let's break this case:
assert(start_of_case->tok->kind == FormToken::TokenKind::OPEN_PAREN);
auto end_of_case = start_of_case->paren;
assert(end_of_case->tok->kind == FormToken::TokenKind::CLOSE_PAREN);
// get the first thing in the case
// and break there.
breakList(pool, start_of_case);
// now, look for the next case.
auto next = end_of_case->next;
while (next &&
(next->is_line_separator || next->tok->kind == FormToken::TokenKind::WHITESPACE)) {
next = next->next;
}
if (!next) {
break;
}
if (next->tok->kind == FormToken::TokenKind::CLOSE_PAREN) {
break;
}
if (next->tok->kind != FormToken::TokenKind::OPEN_PAREN) {
break;
}
start_of_case = next;
}
// break cond into a multi-line always
breakList(pool, node->paren);
}
}
}
+7
View File
@@ -267,6 +267,13 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
assert(false);
}
if (m_value.is_var()) {
auto input_var_type = env.get_types_before_op(m_my_idx).get(m_value.var().reg());
if (env.dts->ts.tc(TypeSpec("uinteger"), input_var_type.typespec())) {
cast_type.insert(cast_type.begin(), 'u');
}
}
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
auto cast_source = pool.alloc_single_element_form<CastElement>(
+4
View File
@@ -1467,6 +1467,10 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "!=";
case FixedOperatorKind::METHOD_OF_OBJECT:
return "method-of-object";
case FixedOperatorKind::NULLP:
return "null?";
case FixedOperatorKind::PAIRP:
return "pair?";
default:
assert(false);
}
+16 -1
View File
@@ -436,11 +436,26 @@ class ConditionElement : public FormElement {
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types);
FormElement* make_zero_check_generic(const Env& env,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types);
FormElement* make_equal_check_generic(const Env& env,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types);
FormElement* make_not_equal_check_generic(const Env& env,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types);
FormElement* make_less_than_zero_signed_check_generic(const Env& env,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types);
FormElement* make_geq_zero_signed_check_generic(const Env& env,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types);
private:
IR2_Condition::Kind m_kind;
+109 -17
View File
@@ -1878,7 +1878,7 @@ FormElement* ConditionElement::make_zero_check_generic(const Env&,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>&) {
// (zero? (+ thing small-integer)) -> (= thing (- small-integer))
assert(source_forms.size() == 1);
auto mr = match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::ADDITION),
{Matcher::any(0), Matcher::any_integer(1)}),
source_forms.at(0));
@@ -1893,6 +1893,109 @@ FormElement* ConditionElement::make_zero_check_generic(const Env&,
}
}
FormElement* ConditionElement::make_equal_check_generic(const Env&,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>&) {
assert(source_forms.size() == 2);
// (= thing '())
auto ref = source_forms.at(1);
auto ref_atom = form_as_atom(ref);
if (ref_atom && ref_atom->get_kind() == SimpleAtom::Kind::EMPTY_LIST) {
// null?
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::NULLP),
source_forms.at(0));
} else {
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::EQ),
source_forms);
}
}
FormElement* ConditionElement::make_not_equal_check_generic(const Env&,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>&) {
assert(source_forms.size() == 2);
// (!= thing '())
auto ref = source_forms.at(1);
auto ref_atom = form_as_atom(ref);
if (ref_atom && ref_atom->get_kind() == SimpleAtom::Kind::EMPTY_LIST) {
// null?
return pool.alloc_element<GenericElement>(
GenericOperator::make_compare(IR2_Condition::Kind::FALSE),
pool.alloc_single_element_form<GenericElement>(
nullptr, GenericOperator::make_fixed(FixedOperatorKind::NULLP), source_forms.at(0)));
} else {
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::NEQ),
source_forms);
}
}
FormElement* ConditionElement::make_less_than_zero_signed_check_generic(
const Env&,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types) {
assert(source_forms.size() == 1);
// (< (shl (the-as int iter) 62) 0) -> (pair? iter)
// match (shl [(the-as int [x]) | [x]] 62)
auto shift_match =
match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
{
Matcher::match_or({Matcher::cast("int", Matcher::any(0)),
Matcher::any(0)}), // the val
Matcher::integer(62) // get the bit in the highest position.
}),
source_forms.at(0));
if (shift_match.matched) {
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::PAIRP),
shift_match.maps.forms.at(0));
} else {
auto casted = make_cast(source_forms, types, TypeSpec("int"), pool);
auto zero = pool.alloc_single_element_form<SimpleAtomElement>(nullptr,
SimpleAtom::make_int_constant(0));
casted.push_back(zero);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::LT),
casted);
}
}
FormElement* ConditionElement::make_geq_zero_signed_check_generic(
const Env&,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types) {
assert(source_forms.size() == 1);
// (>= (shl (the-as int iter) 62) 0) -> (not (pair? iter))
// match (shl [(the-as int [x]) | [x]] 62)
auto shift_match =
match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
{
Matcher::match_or({Matcher::cast("int", Matcher::any(0)),
Matcher::any(0)}), // the val
Matcher::integer(62) // get the bit in the highest position.
}),
source_forms.at(0));
if (shift_match.matched) {
return pool.alloc_element<GenericElement>(
GenericOperator::make_compare(IR2_Condition::Kind::FALSE),
pool.alloc_single_element_form<GenericElement>(
nullptr, GenericOperator::make_fixed(FixedOperatorKind::PAIRP),
shift_match.maps.forms.at(0)));
} else {
auto casted = make_cast(source_forms, types, TypeSpec("int"), pool);
auto zero = pool.alloc_single_element_form<SimpleAtomElement>(nullptr,
SimpleAtom::make_int_constant(0));
casted.push_back(zero);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::GEQ),
casted);
}
}
FormElement* ConditionElement::make_generic(const Env& env,
FormPool& pool,
const std::vector<Form*>& source_forms,
@@ -1911,11 +2014,10 @@ FormElement* ConditionElement::make_generic(const Env& env,
return pool.alloc_element<GenericElement>(GenericOperator::make_compare(m_kind),
source_forms);
case IR2_Condition::Kind::EQUAL:
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::EQ),
source_forms);
return make_equal_check_generic(env, pool, source_forms, types);
case IR2_Condition::Kind::NOT_EQUAL:
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::NEQ),
source_forms);
return make_not_equal_check_generic(env, pool, source_forms, types);
case IR2_Condition::Kind::LESS_THAN_SIGNED:
return pool.alloc_element<GenericElement>(
@@ -1937,12 +2039,7 @@ FormElement* ConditionElement::make_generic(const Env& env,
make_cast(source_forms, types, TypeSpec("int"), pool));
case IR2_Condition::Kind::LESS_THAN_ZERO_SIGNED: {
auto casted = make_cast(source_forms, types, TypeSpec("int"), pool);
auto zero = pool.alloc_single_element_form<SimpleAtomElement>(
nullptr, SimpleAtom::make_int_constant(0));
casted.push_back(zero);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::LT),
casted);
return make_less_than_zero_signed_check_generic(env, pool, source_forms, types);
}
case IR2_Condition::Kind::LEQ_ZERO_SIGNED: {
@@ -1955,12 +2052,7 @@ FormElement* ConditionElement::make_generic(const Env& env,
}
case IR2_Condition::Kind::GEQ_ZERO_SIGNED: {
auto casted = make_cast(source_forms, types, TypeSpec("int"), pool);
auto zero = pool.alloc_single_element_form<SimpleAtomElement>(
nullptr, SimpleAtom::make_int_constant(0));
casted.push_back(zero);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::GEQ),
casted);
return make_geq_zero_signed_check_generic(env, pool, source_forms, types);
}
case IR2_Condition::Kind::GREATER_THAN_ZERO_UNSIGNED: {
+12 -4
View File
@@ -136,6 +136,8 @@ enum class FixedOperatorKind {
NEQ,
CONS,
METHOD_OF_OBJECT,
NULLP,
PAIRP,
INVALID
};
@@ -154,23 +156,29 @@ struct UseDefInfo {
void disable_use(int op_id) {
for (auto& x : uses) {
if (x.op_id == op_id) {
assert(!x.disabled);
if (x.disabled) {
throw std::runtime_error("Invalid disable use twice");
}
x.disabled = true;
return;
}
}
assert(false);
throw std::runtime_error("Invalid disable use");
}
void disable_def(int op_id) {
for (auto& x : defs) {
if (x.op_id == op_id) {
assert(!x.disabled);
if (x.disabled) {
throw std::runtime_error("Invalid disable def twice");
}
x.disabled = true;
return;
}
}
assert(false);
throw std::runtime_error("Invalid disable def");
}
int use_count() const {
+1 -1
View File
@@ -40,9 +40,9 @@ struct OpenGOALAsm {
bool valid = true;
bool todo = false;
Instruction instr;
std::optional<RegisterAccess> m_dst;
std::vector<std::optional<RegisterAccess>> m_src;
Instruction instr;
OpenGOALAsm::Function func;
std::string full_function_name();
+6 -2
View File
@@ -678,8 +678,12 @@ void clean_up_cond_no_else_final(Function& func, CondNoElseElement* cne) {
auto reg = cne->entries.at(i).false_destination;
assert(reg.has_value());
assert(branch);
assert(branch_info_i.written_and_unused.find(reg->reg()) !=
branch_info_i.written_and_unused.end());
if (branch_info_i.written_and_unused.find(reg->reg()) ==
branch_info_i.written_and_unused.end()) {
throw std::runtime_error("Bad delay slot in clean_up_cond_no_else_final");
}
// assert(branch_info_i.written_and_unused.find(reg->reg()) !=
// branch_info_i.written_and_unused.end());
}
}
+5 -4
View File
@@ -228,10 +228,11 @@ std::string write_from_top_level(const Function& top_level,
auto method_match_result = match(method_def_matcher, &f);
if (method_match_result.matched) {
auto func = file.try_get_function_at_label(method_match_result.maps.label.at(method_label));
if (func) {
if (func && func->guessed_name.kind == FunctionName::FunctionKind::METHOD) {
something_matched = true;
result += fmt::format(";; definition for method of type {}\n",
method_match_result.maps.strings.at(type_name));
result +=
fmt::format(";; definition for method {} of type {}\n", func->guessed_name.method_id,
method_match_result.maps.strings.at(type_name));
if (skip_functions.find(func->guessed_name.to_string()) == skip_functions.end()) {
result += careful_function_to_string(func, dts);
} else {
@@ -248,7 +249,7 @@ std::string write_from_top_level(const Function& top_level,
if (dts.ts.fully_defined_type_exists(name)) {
result += fmt::format(";; definition of type {}\n", name);
result += dts.ts.generate_deftype(dts.ts.lookup_type(name));
result += "\n\n";
result += "\n";
} else {
result += fmt::format(
";; type {} is defined here, but it is unknown to the decompiler\n\n", name);
+3 -3
View File
@@ -13,7 +13,7 @@ namespace decompiler {
bool rewrite_inline_asm_instructions(Form* top_level_form,
FormPool& pool,
Function& f,
const DecompilerTypeSystem& dts) {
const DecompilerTypeSystem&) {
assert(top_level_form);
try {
@@ -37,7 +37,7 @@ bool rewrite_inline_asm_instructions(Form* top_level_form,
// If its an invalid or unsupported exception, skip it
/*lg::warn("[ASM Re-Write] - Unsupported inline assembly instruction kind - [{}]",
asmOp.instr.kind);*/
f.warnings.general_warning(";; Unsupported inline assembly instruction kind - [{}]",
f.warnings.general_warning("Unsupported inline assembly instruction kind - [{}]",
asmOp.instr.kind);
new_entries.push_back(entry);
continue;
@@ -51,7 +51,7 @@ bool rewrite_inline_asm_instructions(Form* top_level_form,
// If its an invalid or unsupported exception, skip it
/*lg::warn("[ASM Re-Write] - Inline assembly instruction marked with TODO - [{}]",
asmOp.full_function_name());*/
f.warnings.general_warning(";; Inline assembly instruction marked with TODO - [{}]",
f.warnings.general_warning("Inline assembly instruction marked with TODO - [{}]",
asmOp.full_function_name());
}
+43 -1
View File
@@ -163,6 +163,42 @@ FormElement* rewrite_as_dotimes(LetElement* in, const Env& env, FormPool& pool)
mr.maps.forms.at(1), body);
}
FormElement* fix_up_abs(LetElement* in, const Env& env, FormPool& pool) {
/*
(let ((v0-0 x)
)
(abs v0-0)
)
*/
if (in->entries().size() != 1) {
return nullptr;
}
// look for setting a temp.
auto temp = in->entries().at(0).dest;
auto temp_name = env.get_variable_name(temp);
Form* src = in->entries().at(0).src;
auto body_matcher =
Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::ABS), {Matcher::any_reg(0)});
auto mr = match(body_matcher, in->body());
if (!mr.matched) {
return nullptr;
}
assert(mr.maps.regs.at(0));
auto abs_var_name = env.get_variable_name(*mr.maps.regs.at(0));
if (abs_var_name != temp_name) {
return nullptr;
}
// success!
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::ABS),
src);
}
/*!
* Attempt to rewrite a let as another form. If it cannot be rewritten, this will return nullptr.
*/
@@ -172,6 +208,11 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool) {
return as_dotimes;
}
auto as_abs = fix_up_abs(in, env, pool);
if (as_abs) {
return as_abs;
}
// nothing matched.
return nullptr;
}
@@ -239,7 +280,8 @@ LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_l
kv.second.lca_form->at(i)->collect_vars(ras, true);
bool uses = false;
for (auto& ra : ras) {
if (env.get_variable_name(ra) == kv.second.var_name) {
if ((ra.reg().get_kind() == Reg::FPR || ra.reg().get_kind() == Reg::GPR) &&
env.get_variable_name(ra) == kv.second.var_name) {
uses = true;
}
}
@@ -148,14 +148,11 @@
},
"(method 2 array)":{
"vars":{"v1-1":"content-type-sym","s5-0":"i","s5-1":"i","s5-2":"i"
,"s5-3":"i","s5-4":"i","s5-5":"i","s5-6":"i","s5-7":"i","s5-8":"i",
"s5-9":"i","s5-10":"i","s5-11":"i"}
"vars":{"v1-1":"content-type-sym"}
},
"(method 3 array)":{
"vars":{"v1-1":"content-type-sym","s5-0":"i","s5-1":"i","s5-2":"i"
,"s5-3":"i","s5-4":"i","s5-5":"i","s5-6":"i","s5-7":"i","s5-8":"i","s5-9":"i","s5-10":"i","s5-11":"i"}
"vars":{"v1-1":"content-type-sym"}
},
"mem-copy!":{
File diff suppressed because it is too large Load Diff
+26 -26
View File
@@ -266,7 +266,7 @@ TEST_F(FormRegressionTest, ExprAbs) {
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function int int)";
std::string expected = "(let ((v0-0 arg0)) (abs v0-0))";
std::string expected = "(abs arg0)";
test_with_expr(func, type, expected);
}
@@ -704,13 +704,13 @@ TEST_F(FormRegressionTest, ExprPairMethod4) {
std::string expected =
"(begin\n"
" (cond\n"
" ((= arg0 (quote ())) (set! v0-0 0))\n"
" ((null? arg0) (set! v0-0 0))\n"
" (else\n"
" (let\n"
" ((v1-1 (cdr arg0)))\n"
" (set! v0-0 1)\n"
" (while\n"
" (and (!= v1-1 (quote ())) (< (shl (the-as int v1-1) 62) 0))\n"
" (and (not (null? v1-1)) (pair? v1-1))\n"
" (+! v0-0 1)\n"
" (set! v1-1 (cdr v1-1))\n"
" )\n"
@@ -762,7 +762,7 @@ TEST_F(FormRegressionTest, ExprLast) {
std::string expected =
"(let\n"
" ((v0-0 arg0))\n"
" (while (!= (cdr v0-0) (quote ())) (nop!) (nop!) (set! v0-0 (cdr v0-0)))\n"
" (while (not (null? (cdr v0-0))) (nop!) (nop!) (set! v0-0 (cdr v0-0)))\n"
" v0-0\n"
" )";
test_with_expr(func, type, expected, true, "");
@@ -812,10 +812,10 @@ TEST_F(FormRegressionTest, ExprMember) {
"(let\n"
" ((v1-0 arg1))\n"
" (while\n"
" (not (or (= v1-0 (quote ())) (= (car v1-0) arg0)))\n"
" (not (or (null? v1-0) (= (car v1-0) arg0)))\n"
" (set! v1-0 (cdr v1-0))\n"
" )\n"
" (if (!= v1-0 (quote ())) v1-0)\n"
" (if (not (null? v1-0)) v1-0)\n"
" )";
test_with_expr(func, type, expected, true, "");
}
@@ -874,10 +874,10 @@ TEST_F(FormRegressionTest, ExprNmember) {
std::string expected =
"(begin\n"
" (while\n"
" (not (or (= arg1 '()) (name= (the-as basic (car arg1)) arg0)))\n"
" (not (or (null? arg1) (name= (the-as basic (car arg1)) arg0)))\n"
" (set! arg1 (cdr arg1))\n"
" )\n"
" (if (!= arg1 '()) arg1)\n"
" (if (not (null? arg1)) arg1)\n"
" )";
test_with_expr(func, type, expected, true, "");
}
@@ -925,10 +925,10 @@ TEST_F(FormRegressionTest, ExprAssoc) {
"(let\n"
" ((v1-0 arg1))\n"
" (while\n"
" (not (or (= v1-0 (quote ())) (= (car (car v1-0)) arg0)))\n"
" (not (or (null? v1-0) (= (car (car v1-0)) arg0)))\n"
" (set! v1-0 (cdr v1-0))\n"
" )\n"
" (if (!= v1-0 (quote ())) (car v1-0))\n"
" (if (not (null? v1-0)) (car v1-0))\n"
" )";
test_with_expr(func, type, expected, true, "");
}
@@ -989,14 +989,14 @@ TEST_F(FormRegressionTest, ExprAssoce) {
" (while\n"
" (not\n"
" (or\n"
" (= v1-0 (quote ()))\n"
" (null? v1-0)\n"
" (= (car (car v1-0)) arg0)\n"
" (= (car (car v1-0)) (quote else))\n"
" )\n"
" )\n"
" (set! v1-0 (cdr v1-0))\n"
" )\n"
" (if (!= v1-0 (quote ())) (car v1-0))\n"
" (if (not (null? v1-0)) (car v1-0))\n"
" )";
test_with_expr(func, type, expected, true, "");
}
@@ -1074,7 +1074,7 @@ TEST_F(FormRegressionTest, ExprNassoc) {
" (while\n"
" (not\n"
" (or\n"
" (= arg1 (quote ()))\n"
" (null? arg1)\n"
" (let\n"
" ((a1-1 (car (car arg1))))\n"
" (if\n"
@@ -1087,7 +1087,7 @@ TEST_F(FormRegressionTest, ExprNassoc) {
" )\n"
" (set! arg1 (cdr arg1))\n"
" )\n"
" (if (!= arg1 (quote ())) (car arg1))\n"
" (if (not (null? arg1)) (car arg1))\n"
" )";
test_with_expr(func, type, expected, true, "");
}
@@ -1176,7 +1176,7 @@ TEST_F(FormRegressionTest, ExprNassoce) {
" (while\n"
" (not\n"
" (or\n"
" (= arg1 (quote ()))\n"
" (null? arg1)\n"
" (let\n"
" ((s4-0 (car (car arg1))))\n"
" (if\n"
@@ -1192,7 +1192,7 @@ TEST_F(FormRegressionTest, ExprNassoce) {
" )\n"
" (set! arg1 (cdr arg1))\n"
" )\n"
" (if (!= arg1 (quote ())) (car arg1))\n"
" (if (not (null? arg1)) (car arg1))\n"
" )";
test_with_expr(func, type, expected, true, "");
}
@@ -1243,12 +1243,12 @@ TEST_F(FormRegressionTest, ExprAppend) {
std::string expected =
"(cond\n"
" ((= arg0 (quote ())) arg1)\n"
" ((null? arg0) arg1)\n"
" (else\n"
" (let\n"
" ((v1-1 arg0))\n"
" (while (!= (cdr v1-1) (quote ())) (nop!) (nop!) (set! v1-1 (cdr v1-1)))\n"
" (if (!= v1-1 (quote ())) (set! (cdr v1-1) arg1))\n"
" (while (not (null? (cdr v1-1))) (nop!) (nop!) (set! v1-1 (cdr v1-1)))\n"
" (if (not (null? v1-1)) (set! (cdr v1-1) arg1))\n"
" )\n"
" arg0\n"
" )\n"
@@ -1320,11 +1320,11 @@ TEST_F(FormRegressionTest, ExprDelete) {
" (let\n"
" ((v1-1 arg1) (a2-0 (cdr arg1)))\n"
" (while\n"
" (not (or (= a2-0 (quote ())) (= (car a2-0) arg0)))\n"
" (not (or (null? a2-0) (= (car a2-0) arg0)))\n"
" (set! v1-1 a2-0)\n"
" (set! a2-0 (cdr a2-0))\n"
" )\n"
" (if (!= a2-0 (quote ())) (set! (cdr v1-1) (cdr a2-0)))\n"
" (if (not (null? a2-0)) (set! (cdr v1-1) (cdr a2-0)))\n"
" )\n"
" arg1\n"
" )\n"
@@ -1399,11 +1399,11 @@ TEST_F(FormRegressionTest, ExprDeleteCar) {
" (let\n"
" ((v1-2 arg1) (a2-0 (cdr arg1)))\n"
" (while\n"
" (not (or (= a2-0 (quote ())) (= (car (car a2-0)) arg0)))\n"
" (not (or (null? a2-0) (= (car (car a2-0)) arg0)))\n"
" (set! v1-2 a2-0)\n"
" (set! a2-0 (cdr a2-0))\n"
" )\n"
" (if (!= a2-0 (quote ())) (set! (cdr v1-2) (cdr a2-0)))\n"
" (if (not (null? a2-0)) (set! (cdr v1-2) (cdr a2-0)))\n"
" )\n"
" arg1\n"
" )\n"
@@ -1560,7 +1560,7 @@ TEST_F(FormRegressionTest, ExprSort) {
" ((s3-0 arg0))\n"
" (while\n"
" (not\n"
" (or (= (cdr s3-0) (quote ())) (>= (shl (the-as int (cdr s3-0)) 62) 0))\n"
" (or (null? (cdr s3-0)) (not (pair? (cdr s3-0))))\n"
" )\n"
" (let*\n"
" ((s2-0 (car s3-0)) (s1-0 (car (cdr s3-0))) (v1-1 (arg1 s2-0 s1-0)))\n"
@@ -1858,7 +1858,7 @@ TEST_F(FormRegressionTest, ExprMemCopy) {
" ((v0-0 arg0))\n"
" (dotimes\n"
" (v1-0 arg2)\n"
" (set! (-> (the-as (pointer int8) arg0)) (-> (the-as (pointer uint8) arg1)))\n"
" (set! (-> (the-as (pointer uint8) arg0)) (-> (the-as (pointer uint8) arg1)))\n"
" (&+! arg0 1)\n"
" (&+! arg1 1)\n"
" )\n"
@@ -1940,7 +1940,7 @@ TEST_F(FormRegressionTest, ExprMemOr) {
" (dotimes\n"
" (v1-0 arg2)\n"
" (set!\n"
" (-> (the-as (pointer int8) arg0))\n"
" (-> (the-as (pointer uint8) arg0))\n"
" (logior\n"
" (-> (the-as (pointer uint8) arg0))\n"
" (-> (the-as (pointer uint8) arg1))\n"
+13 -4
View File
@@ -39,20 +39,29 @@ const std::unordered_set<std::string> expected_skip_in_decompiler = {
};
const std::unordered_set<std::string> skip_in_compiling = {
//////////////////////
// GCOMMON
//////////////////////
// these functions are not implemented by the compiler in OpenGOAL, but are in GOAL.
"abs", "ash", "min", "max", "lognor",
// weird PS2 specific debug registers:
"breakpoint-range-set!",
// these require 128-bit integers. We want these eventually, but disabling for now to focus
// on more important issues.
"(method 3 vec4s)", "(method 2 vec4s)",
// these should pass eventually
"(method 2 array)", "(method 3 array)", "valid?", "mem-copy!", "qmem-copy<-!", "qmem-copy->!",
"mem-or!", "breakpoint-range-set!", "print", "printl", "inspect"};
"(method 3 vec4s)", "(method 2 vec4s)", "qmem-copy<-!", "qmem-copy->!", "(method 2 array)",
"(method 3 array)",
// does weird stuff with the type system.
"print", "printl", "inspect",
// inline assembly
"valid?"};
// The decompiler does not attempt to insert forward definitions, as this would be part of an
// unimplemented full-program type analysis pass. For now, we manually specify all functions
// that should have a forward definition here.
const std::string g_forward_type_defs =
"(define-extern name= (function basic basic symbol))\n"
// todo - check if recursive?
"(define-extern fact (function int int))";
// default location for the data. It can be changed with a command line argument.