mirror of
https://github.com/open-goal/jak-project
synced 2026-05-31 01:16:12 -04:00
447 lines
18 KiB
C++
447 lines
18 KiB
C++
#include "gtest/gtest.h"
|
|
#include "decompiler/IR2/AtomicOp.h"
|
|
#include "decompiler/IR2/AtomicOpBuilder.h"
|
|
#include "decompiler/Disasm/InstructionParser.h"
|
|
#include "third-party/fmt/core.h"
|
|
#include "third-party/fmt/format.h"
|
|
#include <regex>
|
|
|
|
using namespace decompiler;
|
|
|
|
std::regex labelRegex("^L\\d+:\\s*$");
|
|
|
|
// Auto indents / adds new-lines to a list of assembly lines
|
|
std::string assembly_from_list(std::vector<std::string> assemblyLines) {
|
|
std::string str = "";
|
|
for (std::string line : assemblyLines) {
|
|
if (std::regex_match(line, labelRegex)) {
|
|
str += fmt::format("{}\n", line);
|
|
} else {
|
|
str += fmt::format(" {}\n", line);
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
void test_case(std::string assembly_lines,
|
|
std::vector<std::string> output_lines,
|
|
std::vector<std::vector<std::string>> write_regs,
|
|
std::vector<std::vector<std::string>> read_regs,
|
|
std::vector<std::vector<std::string>> clobbered_regs) {
|
|
InstructionParser parser;
|
|
// convert to Instructions:
|
|
// some MIPS instructions. Can be a sequence of instructions, possibly with labels.
|
|
ParsedProgram prg = parser.parse_program(assembly_lines);
|
|
|
|
// this verifies we can convert from a string to an instruction, and back to a string again.
|
|
// the instruction printer will add two leading spaces and a newline.
|
|
EXPECT_EQ(prg.print(), assembly_lines);
|
|
|
|
// next, set up a test environment for the conversion. The FunctionAtomicOps will hold
|
|
// the result of the conversion
|
|
FunctionAtomicOps container;
|
|
|
|
// treat the entire program as a single basic block, and convert!
|
|
convert_block_to_atomic_ops(0, prg.instructions.begin(), prg.instructions.end(), prg.labels,
|
|
&container);
|
|
|
|
// count operations
|
|
EXPECT_EQ(container.ops.size(), output_lines.size());
|
|
|
|
// for now, we create an empty environment. The environment will be used in the future to
|
|
// rename register to variables, but for now, we just leave it empty and the printing will
|
|
// use register names
|
|
Env env;
|
|
|
|
// check the we get the right result:
|
|
for (size_t i = 0; i < container.ops.size(); i++) {
|
|
const auto& op = container.ops.at(i);
|
|
EXPECT_EQ(op->to_string(prg.labels, &env), output_lines.at(i));
|
|
|
|
// check that the registers read/written are identified for the operation
|
|
|
|
// check write registers
|
|
EXPECT_EQ(op->write_regs().size(), write_regs.at(i).size());
|
|
for (size_t j = 0; j < op->write_regs().size(); j++) {
|
|
const std::string expected_reg = op->write_regs().at(j).to_string();
|
|
// the ordering of the registers doesn't matter. It could happen to be in the same order
|
|
// as the opcode here, but it may not always be the case.
|
|
bool found = false;
|
|
for (const std::string reg : write_regs.at(i)) {
|
|
// TODO - is there a potential bug here in the event that either list has duplicate
|
|
// registers?
|
|
if (reg == expected_reg) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(found) << fmt::format("Unable to find expected WRITE register - {}",
|
|
expected_reg);
|
|
}
|
|
|
|
// check read registers
|
|
EXPECT_EQ(op->read_regs().size(), read_regs.at(i).size());
|
|
for (size_t j = 0; j < op->read_regs().size(); j++) {
|
|
const std::string expected_reg = op->read_regs().at(j).to_string();
|
|
// the ordering of the registers doesn't matter. It could happen to be in the same order
|
|
// as the opcode here, but it may not always be the case.
|
|
bool found = false;
|
|
for (const std::string reg : read_regs.at(i)) {
|
|
// TODO - is there a potential bug here in the event that either list has duplicate
|
|
// registers?
|
|
if (reg == expected_reg) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(found) << fmt::format("Unable to find expected READ register - {}", expected_reg);
|
|
}
|
|
|
|
// check clobbered registers
|
|
EXPECT_EQ(op->clobber_regs().size(), clobbered_regs.at(i).size());
|
|
for (size_t j = 0; j < op->clobber_regs().size(); j++) {
|
|
const std::string expected_reg = op->clobber_regs().at(j).to_string();
|
|
// the ordering of the registers doesn't matter. It could happen to be in the same order
|
|
// as the opcode here, but it may not always be the case.
|
|
bool found = false;
|
|
for (const std::string reg : clobbered_regs.at(i)) {
|
|
// TODO - is there a potential bug here in the event that either list has duplicate
|
|
// registers?
|
|
if (reg == expected_reg) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(found) << fmt::format("Unable to find expected CLOBBERED register - {}",
|
|
expected_reg);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, Example) {
|
|
test_case(assembly_from_list({"and v0, v1, a3", "and a1, a2, a2"}),
|
|
{"(set! v0 (logand v1 a3))", "(set! a1 (logand a2 a2))"}, {{"v0"}, {"a1"}},
|
|
{{"v1", "a3"}, {"a2", "a2"}}, {{}, {}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, ABS_S) {
|
|
test_case(assembly_from_list({"abs.s f1, f2"}), {"(set! f1 (abs.s f2))"}, {{"f1"}}, {{"f2"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, ADDIU) {
|
|
test_case(assembly_from_list({"addiu a1, r0, 12"}), {"(set! a1 12)"}, {{"a1"}}, {{}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, ADD_S) {
|
|
test_case(assembly_from_list({"add.s f1, f2, f3"}), {"(set! f1 (+.s f2 f3))"}, {{"f1"}},
|
|
{{"f2", "f3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, AND) {
|
|
test_case(assembly_from_list({"and a1, a2, a3"}), {"(set! a1 (logand a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, ANDI) {
|
|
test_case(assembly_from_list({"andi a1, a2, 1234"}), {"(set! a1 (logand a2 1234))"}, {{"a1"}},
|
|
{{"a2"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, CVT_S_W) {
|
|
test_case(assembly_from_list({"cvt.s.w f1, f2"}), {"(set! f1 (i2f f2))"}, {{"f1"}}, {{"f2"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, CVT_W_S) {
|
|
test_case(assembly_from_list({"cvt.w.s f1, f2"}), {"(set! f1 (f2i f2))"}, {{"f1"}}, {{"f2"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DADDIU) {
|
|
test_case(assembly_from_list({"daddiu a1, s7, test"}), {"(set! a1 'test)"}, {{"a1"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"daddiu a1, s7, -10"}), {"(set! a1 '())"}, {{"a1"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"daddiu a1, s7, -32768"}), {"(set! a1 __START-OF-TABLE__)"},
|
|
{{"a1"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"daddiu a1, s7, 8"}), {"(set! a1 '#t)"}, {{"a1"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"L123:", "daddiu a1, fp, L123"}), {"(set! a1 L123)"}, {{"a1"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"daddiu a1, a2, 1234"}), {"(set! a1 (+ a2 1234))"}, {{"a1"}},
|
|
{{"a2"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DADDU) {
|
|
test_case(assembly_from_list({"daddu a1, a2, a3"}), {"(set! a1 (+ a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DIV_S) {
|
|
test_case(assembly_from_list({"div.s f1, f2, f3"}), {"(set! f1 (/.s f2 f3))"}, {{"f1"}},
|
|
{{"f2", "f3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSLL) {
|
|
test_case(assembly_from_list({"dsll a2, a3, 3"}), {"(set! a2 (shl a3 3))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSLL32) {
|
|
test_case(assembly_from_list({"dsll32 a2, a3, 3"}), {"(set! a2 (shl a3 35))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSLLV) {
|
|
test_case(assembly_from_list({"dsllv a1, a2, a3"}), {"(set! a1 (shl a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSRA) {
|
|
test_case(assembly_from_list({"dsra a2, a3, 3"}), {"(set! a2 (sra a3 3))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSRA32) {
|
|
test_case(assembly_from_list({"dsra32 a2, a3, 3"}), {"(set! a2 (sra a3 35))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSRAV) {
|
|
test_case(assembly_from_list({"dsrav a1, a2, a3"}), {"(set! a1 (sra a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSRL) {
|
|
test_case(assembly_from_list({"dsrl a2, a3, 3"}), {"(set! a2 (srl a3 3))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSRL32) {
|
|
test_case(assembly_from_list({"dsrl32 a2, a3, 3"}), {"(set! a2 (srl a3 35))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSRLV) {
|
|
test_case(assembly_from_list({"dsrlv a1, a2, a3"}), {"(set! a1 (srl a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, DSUBU) {
|
|
test_case(assembly_from_list({"dsubu a1, a2, a3"}), {"(set! a1 (- a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
test_case(assembly_from_list({"dsubu a1, r0, a3"}), {"(set! a1 (- a3))"}, {{"a1"}}, {{"a3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LB) {
|
|
test_case(assembly_from_list({"L123:", "lb a3, L123(fp)"}), {"(set! a3 (l.b L123))"}, {{"a3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"lb a2, 0(a3)"}), {"(set! a2 (l.b a3))"}, {{"a2"}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"lb a2, 12(a3)"}), {"(set! a2 (l.b (+ a3 12)))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LBU) {
|
|
test_case(assembly_from_list({"L123:", "lbu a3, L123(fp)"}), {"(set! a3 (l.bu L123))"}, {{"a3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"lbu a2, 0(a3)"}), {"(set! a2 (l.bu a3))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"lbu a2, 12(a3)"}), {"(set! a2 (l.bu (+ a3 12)))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LD) {
|
|
test_case(assembly_from_list({"L123:", "ld a3, L123(fp)"}), {"(set! a3 (l.d L123))"}, {{"a3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"ld a2, 0(a3)"}), {"(set! a2 (l.d a3))"}, {{"a2"}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"ld a2, 12(a3)"}), {"(set! a2 (l.d (+ a3 12)))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LH) {
|
|
test_case(assembly_from_list({"L123:", "lh a3, L123(fp)"}), {"(set! a3 (l.h L123))"}, {{"a3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"lh a2, 0(a3)"}), {"(set! a2 (l.h a3))"}, {{"a2"}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"lh a2, 12(a3)"}), {"(set! a2 (l.h (+ a3 12)))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LHU) {
|
|
test_case(assembly_from_list({"L123:", "lhu a3, L123(fp)"}), {"(set! a3 (l.hu L123))"}, {{"a3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"lhu a2, 0(a3)"}), {"(set! a2 (l.hu a3))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"lhu a2, 12(a3)"}), {"(set! a2 (l.hu (+ a3 12)))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LUI) {
|
|
test_case(assembly_from_list({"lui a3, 2"}), {"(set! a3 131072)"}, {{"a3"}}, {{}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LW) {
|
|
test_case(assembly_from_list({"lw r0, 2(r0)"}), {"(break!)"}, {{}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"lw a2, test(s7)"}), {"(set! a2 test)"}, {{"a2"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"L123:", "lw a3, L123(fp)"}), {"(set! a3 (l.w L123))"}, {{"a3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"lw a2, 0(a3)"}), {"(set! a2 (l.w a3))"}, {{"a2"}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"lw a2, 12(a3)"}), {"(set! a2 (l.w (+ a3 12)))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LWC1) {
|
|
test_case(assembly_from_list({"L123:", "lwc1 f3, L123(fp)"}), {"(set! f3 (l.f L123))"}, {{"f3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"lwc1 f2, 0(a3)"}), {"(set! f2 (l.f a3))"}, {{"f2"}}, {{"a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"lwc1 f2, 12(a3)"}), {"(set! f2 (l.f (+ a3 12)))"}, {{"f2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, LWU) {
|
|
test_case(assembly_from_list({"L123:", "lwu a3, L123(fp)"}), {"(set! a3 (l.wu L123))"}, {{"a3"}},
|
|
{{}}, {{}});
|
|
test_case(assembly_from_list({"lwu a2, 0(a3)"}), {"(set! a2 (l.wu a3))"}, {{"a2"}}, {{"a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"lwu a2, 12(a3)"}), {"(set! a2 (l.wu (+ a3 12)))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MAX_S) {
|
|
test_case(assembly_from_list({"max.s f1, f2, f3"}), {"(set! f1 (max.s f2 f3))"}, {{"f1"}},
|
|
{{"f2", "f3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MFC1) {
|
|
test_case(assembly_from_list({"mfc1 a1, f3"}), {"(set! a1 (fpr->gpr f3))"}, {{"a1"}}, {{"f3"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MIN_S) {
|
|
test_case(assembly_from_list({"min.s f1, f2, f3"}), {"(set! f1 (min.s f2 f3))"}, {{"f1"}},
|
|
{{"f2", "f3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MOVN) {
|
|
test_case(assembly_from_list({"movn a1, s7, a2"}), {"(cmove-#f-nonzero a1 a2)"}, {{"a1"}},
|
|
{{"a2"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MOVZ) {
|
|
test_case(assembly_from_list({"movz a1, s7, a2"}), {"(cmove-#f-zero a1 a2)"}, {{"a1"}}, {{"a2"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MOV_S) {
|
|
test_case(assembly_from_list({"mov.s f1, f2"}), {"(set! f1 f2)"}, {{"f1"}}, {{"f2"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MTC1) {
|
|
test_case(assembly_from_list({"mtc1 f3, a1"}), {"(set! f3 (gpr->fpr a1))"}, {{"f3"}}, {{"a1"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MULT3) {
|
|
test_case(assembly_from_list({"mult3 a1, a2, a3"}), {"(set! a1 (*.si a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MULTU3) {
|
|
test_case(assembly_from_list({"multu3 a1, a2, a3"}), {"(set! a1 (*.ui a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, MUL_S) {
|
|
test_case(assembly_from_list({"mul.s f1, f2, f3"}), {"(set! f1 (*.s f2 f3))"}, {{"f1"}},
|
|
{{"f2", "f3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, NEG_S) {
|
|
test_case(assembly_from_list({"neg.s f1, f2"}), {"(set! f1 (neg.s f2))"}, {{"f1"}}, {{"f2"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, NOR) {
|
|
test_case(assembly_from_list({"nor a1, a2, r0"}), {"(set! a1 (lognot a2))"}, {{"a1"}}, {{"a2"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"nor a1, a2, a3"}), {"(set! a1 (lognor a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, OR) {
|
|
test_case(assembly_from_list({"or a1, a2, a3"}), {"(set! a1 (logior a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
test_case(assembly_from_list({"or a2, r0, r0"}), {"(set! a2 0)"}, {{"a2"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"or a1, s7, r0"}), {"(set! a1 '#f)"}, {{"a1"}}, {{}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, ORI) {
|
|
test_case(assembly_from_list({"ori a2, r0, 1234"}), {"(set! a2 1234)"}, {{"a2"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"ori a2, r0, -1234"}), {"(set! a2 -1234)"}, {{"a2"}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"ori a2, a3, -1234"}), {"(set! a2 (logior a3 -1234))"}, {{"a2"}},
|
|
{{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SB) {
|
|
test_case(assembly_from_list({"sb a1, 2(a3)"}), {"(s.b! (+ a3 2) a1)"}, {{}}, {{"a1", "a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"sb a1, 0(a3)"}), {"(s.b! a3 a1)"}, {{}}, {{"a1", "a3"}}, {{}});
|
|
test_case(assembly_from_list({"sb s7, 2(a3)"}), {"(s.b! (+ a3 2) '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"sb s7, 0(a3)"}), {"(s.b! a3 '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SD) {
|
|
test_case(assembly_from_list({"sd a1, 2(a3)"}), {"(s.d! (+ a3 2) a1)"}, {{}}, {{"a1", "a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"sd a1, 0(a3)"}), {"(s.d! a3 a1)"}, {{}}, {{"a1", "a3"}}, {{}});
|
|
test_case(assembly_from_list({"sd s7, 2(a3)"}), {"(s.d! (+ a3 2) '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"sd s7, 0(a3)"}), {"(s.d! a3 '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SH) {
|
|
test_case(assembly_from_list({"sh a1, 2(a3)"}), {"(s.h! (+ a3 2) a1)"}, {{}}, {{"a1", "a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"sh a1, 0(a3)"}), {"(s.h! a3 a1)"}, {{}}, {{"a1", "a3"}}, {{}});
|
|
test_case(assembly_from_list({"sh s7, 2(a3)"}), {"(s.h! (+ a3 2) '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"sh s7, 0(a3)"}), {"(s.h! a3 '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SLL) {
|
|
test_case(assembly_from_list({"sll r0, r0, 0"}), {"(nop!)"}, {{}}, {{}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SQRT_S) {
|
|
test_case(assembly_from_list({"sqrt.s f1, f2"}), {"(set! f1 (sqrt.s f2))"}, {{"f1"}}, {{"f2"}},
|
|
{{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SUB_S) {
|
|
test_case(assembly_from_list({"sub.s f1, f2, f3"}), {"(set! f1 (-.s f2 f3))"}, {{"f1"}},
|
|
{{"f2", "f3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SW) {
|
|
test_case(assembly_from_list({"sw a1, test(s7)"}), {"(s.w! test a1)"}, {{}}, {{"a1"}}, {{}});
|
|
test_case(assembly_from_list({"sw s7, test(s7)"}), {"(s.w! test '#f)"}, {{}}, {{}}, {{}});
|
|
test_case(assembly_from_list({"sw a1, 2(a3)"}), {"(s.w! (+ a3 2) a1)"}, {{}}, {{"a1", "a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"sw a1, 0(a3)"}), {"(s.w! a3 a1)"}, {{}}, {{"a1", "a3"}}, {{}});
|
|
test_case(assembly_from_list({"sw s7, 2(a3)"}), {"(s.w! (+ a3 2) '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
test_case(assembly_from_list({"sw s7, 0(a3)"}), {"(s.w! a3 '#f)"}, {{}}, {{"a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, SWC1) {
|
|
test_case(assembly_from_list({"swc1 f2, 2(a3)"}), {"(s.f! (+ a3 2) f2)"}, {{}}, {{"f2", "a3"}},
|
|
{{}});
|
|
test_case(assembly_from_list({"swc1 f2, 0(a3)"}), {"(s.f! a3 f2)"}, {{}}, {{"f2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, XOR) {
|
|
test_case(assembly_from_list({"xor a1, a2, a3"}), {"(set! a1 (logxor a2 a3))"}, {{"a1"}},
|
|
{{"a2", "a3"}}, {{}});
|
|
}
|
|
|
|
TEST(DecompilerAtomicOpBuilder, XORI) {
|
|
test_case(assembly_from_list({"xori a1, a2, 1234"}), {"(set! a1 (logxor a2 1234))"}, {{"a1"}},
|
|
{{"a2"}}, {{}});
|
|
}
|