mirror of
https://github.com/open-goal/jak-project
synced 2026-08-19 22:12:24 -04:00
[Decompiler] Begin expression conversion, rearrange tests (#209)
* refactor tests and analysis passes * identity test working * combine test categories with only a few cases * more fixes
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
#include "FormRegressionTest.h"
|
||||
|
||||
#include "decompiler/analysis/variable_naming.h"
|
||||
#include "decompiler/analysis/reg_usage.h"
|
||||
#include "decompiler/analysis/cfg_builder.h"
|
||||
#include "decompiler/analysis/expression_build.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
|
||||
using namespace decompiler;
|
||||
|
||||
void FormRegressionTest::SetUpTestCase() {
|
||||
parser = std::make_unique<InstructionParser>();
|
||||
dts = std::make_unique<DecompilerTypeSystem>();
|
||||
dts->parse_type_defs({"decompiler", "config", "all-types.gc"});
|
||||
}
|
||||
|
||||
void FormRegressionTest::TearDownTestCase() {
|
||||
parser.reset();
|
||||
dts.reset();
|
||||
parser.reset();
|
||||
}
|
||||
|
||||
void FormRegressionTest::TestData::add_string_at_label(const std::string& label_name,
|
||||
const std::string& data) {
|
||||
// first, align segment 1:
|
||||
while (file.words_by_seg.at(1).size() % 4) {
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(0));
|
||||
}
|
||||
|
||||
// add string type tag:
|
||||
LinkedWord type_tag(0);
|
||||
type_tag.kind = LinkedWord::Kind::TYPE_PTR;
|
||||
type_tag.symbol_name = "string";
|
||||
file.words_by_seg.at(1).push_back(type_tag);
|
||||
int string_start = 4 * int(file.words_by_seg.at(1).size());
|
||||
|
||||
// add size
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(int(data.length())));
|
||||
|
||||
// add string:
|
||||
std::vector<char> bytes;
|
||||
bytes.resize(((data.size() + 1 + 3) / 4) * 4);
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
bytes[i] = data[i];
|
||||
}
|
||||
for (size_t i = 0; i < bytes.size() / 4; i++) {
|
||||
auto word = ((uint32_t*)bytes.data())[i];
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(word));
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(0));
|
||||
}
|
||||
// will be already null terminated.
|
||||
|
||||
for (auto& label : file.labels) {
|
||||
if (label.name == label_name) {
|
||||
label.target_segment = 1;
|
||||
label.offset = string_start;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
|
||||
std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
const std::string& code,
|
||||
const TypeSpec& function_type,
|
||||
bool do_expressions,
|
||||
bool allow_pairs,
|
||||
const std::string& method_name,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings) {
|
||||
dts->type_prop_settings.locked = true;
|
||||
dts->type_prop_settings.reset();
|
||||
dts->type_prop_settings.allow_pair = allow_pairs;
|
||||
dts->type_prop_settings.current_method_type = method_name;
|
||||
auto program = parser->parse_program(code);
|
||||
// printf("prg:\n%s\n\n", program.print().c_str());
|
||||
auto test = std::make_unique<TestData>(program.instructions.size());
|
||||
test->file.words_by_seg.resize(3);
|
||||
test->file.labels = program.labels;
|
||||
test->func.ir2.env.file = &test->file;
|
||||
test->func.instructions = program.instructions;
|
||||
test->func.guessed_name.set_as_global("test-function");
|
||||
test->func.type = function_type;
|
||||
|
||||
for (auto& str : strings) {
|
||||
test->add_string_at_label(str.first, str.second);
|
||||
}
|
||||
|
||||
test->func.basic_blocks = find_blocks_in_function(test->file, 0, test->func);
|
||||
test->func.analyze_prologue(test->file);
|
||||
test->func.cfg = build_cfg(test->file, 0, test->func);
|
||||
EXPECT_TRUE(test->func.cfg->is_fully_resolved());
|
||||
|
||||
auto ops = convert_function_to_atomic_ops(test->func, program.labels);
|
||||
test->func.ir2.atomic_ops = std::make_shared<FunctionAtomicOps>(std::move(ops));
|
||||
test->func.ir2.atomic_ops_succeeded = true;
|
||||
|
||||
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, {}));
|
||||
|
||||
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
|
||||
|
||||
auto result = run_variable_renaming(test->func, test->func.ir2.env.reg_use(),
|
||||
*test->func.ir2.atomic_ops, *dts);
|
||||
if (result.has_value()) {
|
||||
test->func.ir2.env.set_local_vars(*result);
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
|
||||
build_initial_forms(test->func);
|
||||
EXPECT_TRUE(test->func.ir2.top_form);
|
||||
|
||||
// for now, just test that this can at least be called.
|
||||
VariableSet vars;
|
||||
test->func.ir2.top_form->collect_vars(vars);
|
||||
|
||||
if (do_expressions) {
|
||||
bool success =
|
||||
convert_to_expressions(test->func.ir2.top_form, test->func.ir2.form_pool, test->func);
|
||||
|
||||
EXPECT_TRUE(success);
|
||||
if (!success) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
void FormRegressionTest::test(const std::string& code,
|
||||
const std::string& type,
|
||||
const std::string& expected,
|
||||
bool do_expressions,
|
||||
bool allow_pairs,
|
||||
const std::string& method_name,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings) {
|
||||
auto ts = dts->parse_type_spec(type);
|
||||
auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings);
|
||||
ASSERT_TRUE(test);
|
||||
auto expected_form =
|
||||
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
|
||||
auto actual_form =
|
||||
pretty_print::get_pretty_printer_reader()
|
||||
.read_from_string(test->func.ir2.top_form->to_form(test->func.ir2.env).print(), false)
|
||||
.as_pair()
|
||||
->car;
|
||||
if (expected_form != actual_form) {
|
||||
printf("Got:\n%s\n\nExpected\n%s\n", actual_form.print().c_str(),
|
||||
expected_form.print().c_str());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(expected_form == actual_form);
|
||||
}
|
||||
|
||||
std::unique_ptr<InstructionParser> FormRegressionTest::parser;
|
||||
std::unique_ptr<DecompilerTypeSystem> FormRegressionTest::dts;
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "gtest/gtest.h"
|
||||
#include "decompiler/Disasm/InstructionParser.h"
|
||||
#include "decompiler/util/DecompilerTypeSystem.h"
|
||||
#include "decompiler/Function/Function.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
|
||||
class FormRegressionTest : public ::testing::Test {
|
||||
protected:
|
||||
static std::unique_ptr<decompiler::InstructionParser> parser;
|
||||
static std::unique_ptr<decompiler::DecompilerTypeSystem> dts;
|
||||
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
struct TestData {
|
||||
explicit TestData(int instrs) : func(0, instrs) {}
|
||||
decompiler::Function func;
|
||||
decompiler::LinkedObjectFile file;
|
||||
|
||||
void add_string_at_label(const std::string& label_name, const std::string& data);
|
||||
};
|
||||
|
||||
std::unique_ptr<TestData> make_function(
|
||||
const std::string& code,
|
||||
const TypeSpec& function_type,
|
||||
bool do_expressions,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {});
|
||||
|
||||
void test(const std::string& code,
|
||||
const std::string& type,
|
||||
const std::string& expected,
|
||||
bool do_expressions,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {});
|
||||
|
||||
void test_no_expr(const std::string& code,
|
||||
const std::string& type,
|
||||
const std::string& expected,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
|
||||
test(code, type, expected, false, allow_pairs, method_name, strings);
|
||||
}
|
||||
|
||||
void test_with_expr(const std::string& code,
|
||||
const std::string& type,
|
||||
const std::string& expected,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
|
||||
test(code, type, expected, true, allow_pairs, method_name, strings);
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "decompiler/IR2/AtomicOp.h"
|
||||
#include "decompiler/IR2/atomic_op_builder.h"
|
||||
#include "decompiler/analysis/atomic_op_builder.h"
|
||||
#include "decompiler/Disasm/InstructionParser.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "third-party/fmt/format.h"
|
||||
|
||||
+41
-194
@@ -1,162 +1,9 @@
|
||||
#include <memory>
|
||||
#include "gtest/gtest.h"
|
||||
#include "decompiler/Disasm/InstructionParser.h"
|
||||
#include "decompiler/Disasm/DecompilerLabel.h"
|
||||
#include "decompiler/Function/Function.h"
|
||||
#include "decompiler/ObjectFile/ObjectFileDB.h"
|
||||
#include "decompiler/IR2/variable_naming.h"
|
||||
#include "decompiler/IR2/cfg_builder.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "FormRegressionTest.h"
|
||||
|
||||
using namespace decompiler;
|
||||
|
||||
class DecompilerRegressionTest : public ::testing::Test {
|
||||
protected:
|
||||
static std::unique_ptr<InstructionParser> parser;
|
||||
static std::unique_ptr<DecompilerTypeSystem> dts;
|
||||
|
||||
static void SetUpTestCase() {
|
||||
parser = std::make_unique<InstructionParser>();
|
||||
dts = std::make_unique<DecompilerTypeSystem>();
|
||||
dts->parse_type_defs({"decompiler", "config", "all-types.gc"});
|
||||
}
|
||||
|
||||
static void TearDownTestCase() {
|
||||
parser.reset();
|
||||
dts.reset();
|
||||
parser.reset();
|
||||
}
|
||||
|
||||
struct TestData {
|
||||
explicit TestData(int instrs) : func(0, instrs) {}
|
||||
Function func;
|
||||
LinkedObjectFile file;
|
||||
|
||||
void add_string_at_label(const std::string& label_name, const std::string& data) {
|
||||
// first, align segment 1:
|
||||
while (file.words_by_seg.at(1).size() % 4) {
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(0));
|
||||
}
|
||||
|
||||
// add string type tag:
|
||||
LinkedWord type_tag(0);
|
||||
type_tag.kind = LinkedWord::Kind::TYPE_PTR;
|
||||
type_tag.symbol_name = "string";
|
||||
file.words_by_seg.at(1).push_back(type_tag);
|
||||
int string_start = 4 * int(file.words_by_seg.at(1).size());
|
||||
|
||||
// add size
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(int(data.length())));
|
||||
|
||||
// add string:
|
||||
std::vector<char> bytes;
|
||||
bytes.resize(((data.size() + 1 + 3) / 4) * 4);
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
bytes[i] = data[i];
|
||||
}
|
||||
for (size_t i = 0; i < bytes.size() / 4; i++) {
|
||||
auto word = ((uint32_t*)bytes.data())[i];
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(word));
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
file.words_by_seg.at(1).push_back(LinkedWord(0));
|
||||
}
|
||||
// will be already null terminated.
|
||||
|
||||
for (auto& label : file.labels) {
|
||||
if (label.name == label_name) {
|
||||
label.target_segment = 1;
|
||||
label.offset = string_start;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<TestData> make_function(
|
||||
const std::string& code,
|
||||
const TypeSpec& function_type,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
|
||||
dts->type_prop_settings.locked = true;
|
||||
dts->type_prop_settings.reset();
|
||||
dts->type_prop_settings.allow_pair = allow_pairs;
|
||||
dts->type_prop_settings.current_method_type = method_name;
|
||||
auto program = parser->parse_program(code);
|
||||
// printf("prg:\n%s\n\n", program.print().c_str());
|
||||
auto test = std::make_unique<TestData>(program.instructions.size());
|
||||
test->file.words_by_seg.resize(3);
|
||||
test->file.labels = program.labels;
|
||||
test->func.ir2.env.file = &test->file;
|
||||
test->func.instructions = program.instructions;
|
||||
test->func.guessed_name.set_as_global("test-function");
|
||||
|
||||
for (auto& str : strings) {
|
||||
test->add_string_at_label(str.first, str.second);
|
||||
}
|
||||
|
||||
test->func.basic_blocks = find_blocks_in_function(test->file, 0, test->func);
|
||||
test->func.analyze_prologue(test->file);
|
||||
test->func.cfg = build_cfg(test->file, 0, test->func);
|
||||
EXPECT_TRUE(test->func.cfg->is_fully_resolved());
|
||||
|
||||
auto ops = convert_function_to_atomic_ops(test->func, program.labels);
|
||||
test->func.ir2.atomic_ops = std::make_shared<FunctionAtomicOps>(std::move(ops));
|
||||
test->func.ir2.atomic_ops_succeeded = true;
|
||||
|
||||
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, {}));
|
||||
|
||||
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
|
||||
|
||||
auto result = run_variable_renaming(test->func, test->func.ir2.env.reg_use(),
|
||||
*test->func.ir2.atomic_ops, *dts);
|
||||
if (result.has_value()) {
|
||||
test->func.ir2.env.set_local_vars(*result);
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
|
||||
build_initial_forms(test->func);
|
||||
EXPECT_TRUE(test->func.ir2.top_form);
|
||||
|
||||
// for now, just test that this can at least be called.
|
||||
VariableSet vars;
|
||||
test->func.ir2.top_form->collect_vars(vars);
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
void test(const std::string& code,
|
||||
const std::string& type,
|
||||
const std::string& expected,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
|
||||
auto ts = dts->parse_type_spec(type);
|
||||
auto test = make_function(code, ts, allow_pairs, method_name, strings);
|
||||
auto expected_form =
|
||||
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
|
||||
auto actual_form =
|
||||
pretty_print::get_pretty_printer_reader()
|
||||
.read_from_string(test->func.ir2.top_form->to_form(test->func.ir2.env).print(), false)
|
||||
.as_pair()
|
||||
->car;
|
||||
if (expected_form != actual_form) {
|
||||
printf("Got:\n%s\n\nExpected\n%s\n", actual_form.print().c_str(),
|
||||
expected_form.print().c_str());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(expected_form == actual_form);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<InstructionParser> DecompilerRegressionTest::parser;
|
||||
std::unique_ptr<DecompilerTypeSystem> DecompilerRegressionTest::dts;
|
||||
|
||||
TEST_F(DecompilerRegressionTest, StringTest) {
|
||||
TEST_F(FormRegressionTest, StringTest) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L100:\n"
|
||||
@@ -164,7 +11,7 @@ TEST_F(DecompilerRegressionTest, StringTest) {
|
||||
"L101:\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), false, "",
|
||||
auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), false, false, "",
|
||||
{{"L100", "testing-string"}, {"L101", "testing-string-2"}});
|
||||
|
||||
EXPECT_EQ(test->file.get_goal_string_by_label(test->file.get_label_by_name("L100")),
|
||||
@@ -173,7 +20,7 @@ TEST_F(DecompilerRegressionTest, StringTest) {
|
||||
"testing-string-2");
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, SimplestTest) {
|
||||
TEST_F(FormRegressionTest, SimplestTest) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
" or v0, a0, r0\n"
|
||||
@@ -181,10 +28,10 @@ TEST_F(DecompilerRegressionTest, SimplestTest) {
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function object object)";
|
||||
std::string expected = "(set! v0-0 a0-0)";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, FloatingPointBasic) {
|
||||
TEST_F(FormRegressionTest, FloatingPointBasic) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L345:\n"
|
||||
@@ -206,10 +53,10 @@ TEST_F(DecompilerRegressionTest, FloatingPointBasic) {
|
||||
" (set! f0-1 (/.s f0-0 f1-0))\n"
|
||||
" (set! v0-0 (fpr->gpr f0-1))\n"
|
||||
" )";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, Op3) {
|
||||
TEST_F(FormRegressionTest, Op3) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L308:\n"
|
||||
@@ -218,10 +65,10 @@ TEST_F(DecompilerRegressionTest, Op3) {
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int int)";
|
||||
std::string expected = "(set! v0-0 (*.si a0-0 a1-0))";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, Division) {
|
||||
TEST_F(FormRegressionTest, Division) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L307:\n"
|
||||
@@ -231,10 +78,10 @@ TEST_F(DecompilerRegressionTest, Division) {
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int int)";
|
||||
std::string expected = "(set! v0-0 (/.si a0-0 a1-0))";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, Ash) {
|
||||
TEST_F(FormRegressionTest, Ash) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L305:\n"
|
||||
@@ -251,10 +98,10 @@ TEST_F(DecompilerRegressionTest, Ash) {
|
||||
" sll r0, r0, 0";
|
||||
std::string type = "(function int int int)";
|
||||
std::string expected = "(begin (set! v1-0 a0-0) (set! v0-0 (ash.si v1-0 a1-0)))";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, Abs) {
|
||||
TEST_F(FormRegressionTest, Abs) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L301:\n"
|
||||
@@ -267,10 +114,10 @@ TEST_F(DecompilerRegressionTest, Abs) {
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int)";
|
||||
std::string expected = "(begin (set! v0-0 a0-0) (set! v0-1 (abs v0-0)))";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, Min) {
|
||||
TEST_F(FormRegressionTest, Min) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
" or v0, a0, r0\n"
|
||||
@@ -281,10 +128,10 @@ TEST_F(DecompilerRegressionTest, Min) {
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int int)";
|
||||
std::string expected = "(begin (set! v0-0 a0-0) (set! v1-0 a1-0) (set! v0-1 (min.si v0-0 v1-0)))";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, Max) {
|
||||
TEST_F(FormRegressionTest, Max) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L299:\n"
|
||||
@@ -296,10 +143,10 @@ TEST_F(DecompilerRegressionTest, Max) {
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int int)";
|
||||
std::string expected = "(begin (set! v0-0 a0-0) (set! v1-0 a1-0) (set! v0-1 (max.si v0-0 v1-0)))";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, FormatString) {
|
||||
TEST_F(FormRegressionTest, FormatString) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L343:\n"
|
||||
@@ -336,10 +183,10 @@ TEST_F(DecompilerRegressionTest, FormatString) {
|
||||
" (set! v0-0 (call! a0-1 a1-0 a2-0))\n" // #t, "~f", the float
|
||||
" (set! v0-1 gp-0)\n"
|
||||
" )";
|
||||
test(func, type, expected, false, "", {{"L343", "~f"}});
|
||||
test_no_expr(func, type, expected, false, "", {{"L343", "~f"}});
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, WhileLoop) {
|
||||
TEST_F(FormRegressionTest, WhileLoop) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L285:\n"
|
||||
@@ -378,11 +225,11 @@ TEST_F(DecompilerRegressionTest, WhileLoop) {
|
||||
" )\n"
|
||||
" (set! v0-1 '#f)\n"
|
||||
" )";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
// Note - this test looks weird because or's aren't fully processed at this point.
|
||||
TEST_F(DecompilerRegressionTest, Or) {
|
||||
TEST_F(FormRegressionTest, Or) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L280:\n"
|
||||
@@ -443,10 +290,10 @@ TEST_F(DecompilerRegressionTest, Or) {
|
||||
" )\n"
|
||||
" (set! v0-1 '#f)\n"
|
||||
" )";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, DynamicMethodAccess) {
|
||||
TEST_F(FormRegressionTest, DynamicMethodAccess) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
@@ -520,10 +367,10 @@ TEST_F(DecompilerRegressionTest, DynamicMethodAccess) {
|
||||
" )\n"
|
||||
" (set! v1-5 '#f)\n"
|
||||
" )";
|
||||
test(func, type, expected);
|
||||
test_no_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, SimpleLoopMergeCheck) {
|
||||
TEST_F(FormRegressionTest, SimpleLoopMergeCheck) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
@@ -563,10 +410,10 @@ TEST_F(DecompilerRegressionTest, SimpleLoopMergeCheck) {
|
||||
" (set! v1-2 '#f)\n"
|
||||
" (set! v0-0 (l.w (+ a0-0 -2)))\n"
|
||||
" )";
|
||||
test(func, type, expected, true);
|
||||
test_no_expr(func, type, expected, true);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, And) {
|
||||
TEST_F(FormRegressionTest, And) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
@@ -632,10 +479,10 @@ TEST_F(DecompilerRegressionTest, And) {
|
||||
" (set! v1-2 '#f)\n" // while's false, I think.
|
||||
" )\n"
|
||||
" )";
|
||||
test(func, type, expected, true);
|
||||
test_no_expr(func, type, expected, true);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, FunctionCall) {
|
||||
TEST_F(FormRegressionTest, FunctionCall) {
|
||||
// nmember
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
@@ -715,10 +562,10 @@ TEST_F(DecompilerRegressionTest, FunctionCall) {
|
||||
" )\n"
|
||||
" (set! v0-2 gp-0)\n" // not empty, so return the result
|
||||
" )"; // the (set! v0 #f) from the if is added later.
|
||||
test(func, type, expected, true);
|
||||
test_no_expr(func, type, expected, true);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, NestedAndOr) {
|
||||
TEST_F(FormRegressionTest, NestedAndOr) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
@@ -886,10 +733,10 @@ TEST_F(DecompilerRegressionTest, NestedAndOr) {
|
||||
" (set! v1-12 '#f)\n"
|
||||
" (set! v0-1 gp-0)\n"
|
||||
" )";
|
||||
test(func, type, expected, true);
|
||||
test_no_expr(func, type, expected, true);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, NewMethod) {
|
||||
TEST_F(FormRegressionTest, NewMethod) {
|
||||
// inline-array-class new
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
@@ -941,10 +788,10 @@ TEST_F(DecompilerRegressionTest, NewMethod) {
|
||||
" (s.w! v0-0 gp-0)\n" // store size
|
||||
" (s.w! (+ v0-0 4) gp-0)\n"
|
||||
" )";
|
||||
test(func, type, expected, false, "inline-array-class");
|
||||
test_no_expr(func, type, expected, false, "inline-array-class");
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, Recursive) {
|
||||
TEST_F(FormRegressionTest, Recursive) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
@@ -985,10 +832,10 @@ TEST_F(DecompilerRegressionTest, Recursive) {
|
||||
" (set! v0-2 (*.si gp-0 v0-1))\n" // not quite a tail call...
|
||||
" )\n"
|
||||
" )";
|
||||
test(func, type, expected, false);
|
||||
test_no_expr(func, type, expected, false);
|
||||
}
|
||||
|
||||
TEST_F(DecompilerRegressionTest, TypeOf) {
|
||||
TEST_F(FormRegressionTest, TypeOf) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
@@ -1020,5 +867,5 @@ TEST_F(DecompilerRegressionTest, TypeOf) {
|
||||
" (set! t9-0 (l.wu (+ v1-1 24)))\n" // print method.
|
||||
" (set! v0-0 (call! a0-0))\n"
|
||||
" )";
|
||||
test(func, type, expected, false);
|
||||
test_no_expr(func, type, expected, false);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "FormRegressionTest.h"
|
||||
|
||||
using namespace decompiler;
|
||||
|
||||
TEST_F(FormRegressionTest, ExprIdentity) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
" or v0, a0, r0\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function object object)";
|
||||
std::string expected = "a0-0";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprFloatingPoint) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
"L345:\n"
|
||||
" daddiu sp, sp, -16\n"
|
||||
" sd fp, 8(sp)\n"
|
||||
" or fp, t9, r0\n"
|
||||
" lwc1 f0, L345(fp)\n"
|
||||
" mtc1 f1, a0\n"
|
||||
" div.s f0, f0, f1\n"
|
||||
" mfc1 v0, f0\n"
|
||||
" ld fp, 8(sp)\n"
|
||||
" jr ra\n"
|
||||
" daddiu sp, sp, 16";
|
||||
std::string type = "(function float float)";
|
||||
std::string expected = "(/ (l.f L345) a0-0)";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, AdditionSigned) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
" daddu v0, a0, a1\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int int)";
|
||||
std::string expected = "(+ a0-0 a1-0)";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, AdditionUnSigned) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
" daddu v0, a0, a1\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function uint uint uint)";
|
||||
std::string expected = "(+ a0-0 a1-0)";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, AdditionMixed1) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
" daddu v0, a0, a1\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int uint int)";
|
||||
std::string expected = "(+ a0-0 (the-as int a1-0))";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, AdditionMixed2) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
" daddu v0, a0, a1\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function uint int uint)";
|
||||
std::string expected = "(+ a0-0 (the-as uint a1-0))";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
// TODO - test the additions, but with the wrong return types.
|
||||
Reference in New Issue
Block a user