diff --git a/include/ChaiVM/interpreter/executor.hpp b/include/ChaiVM/interpreter/executor.hpp index b9eb83b..4249951 100644 --- a/include/ChaiVM/interpreter/executor.hpp +++ b/include/ChaiVM/interpreter/executor.hpp @@ -50,18 +50,33 @@ class Executor { void icsqrt(Instruction ins); void icsin(Instruction ins); void iccos(Instruction ins); + void if_icmpeq(Instruction ins); + void if_icmpne(Instruction ins); + void if_icmpgt(Instruction ins); + void if_icmpge(Instruction ins); + void if_icmplt(Instruction ins); + void if_icmple(Instruction ins); + void if_acmpeq(Instruction ins); + void if_acmpne(Instruction ins); + void cmpgf(Instruction ins); + void cmplf(Instruction ins); + void g0t0(Instruction ins); - static constexpr Handler handlerArr[] = { - &Executor::inv, &Executor::nop, &Executor::ret, - &Executor::mov, &Executor::ldia, &Executor::ldra, - &Executor::star, &Executor::add, &Executor::addi, - &Executor::sub, &Executor::subi, &Executor::mul, - &Executor::muli, &Executor::div, &Executor::divi, - &Executor::ldiaf, &Executor::addf, &Executor::addif, - &Executor::subf, &Executor::subif, &Executor::mulf, - &Executor::mulif, &Executor::divf, &Executor::divif, - &Executor::icprint, &Executor::icscani, &Executor::icscanf, - &Executor::icsqrt, &Executor::icsin, &Executor::iccos}; + static constexpr Handler HANDLER_ARR[] = { + &Executor::inv, &Executor::nop, &Executor::ret, + &Executor::mov, &Executor::ldia, &Executor::ldra, + &Executor::star, &Executor::add, &Executor::addi, + &Executor::sub, &Executor::subi, &Executor::mul, + &Executor::muli, &Executor::div, &Executor::divi, + &Executor::ldiaf, &Executor::addf, &Executor::addif, + &Executor::subf, &Executor::subif, &Executor::mulf, + &Executor::mulif, &Executor::divf, &Executor::divif, + &Executor::icprint, &Executor::icscani, &Executor::icscanf, + &Executor::icsqrt, &Executor::icsin, &Executor::iccos, + &Executor::if_icmpeq, &Executor::if_icmpne, &Executor::if_icmpgt, + &Executor::if_icmpge, &Executor::if_icmplt, &Executor::if_icmple, + &Executor::if_acmpeq, &Executor::if_acmpne, &Executor::cmpgf, + &Executor::cmplf, &Executor::g0t0}; private: CodeManager *codeManager_; diff --git a/include/ChaiVM/utils/instr2Raw.hpp b/include/ChaiVM/utils/instr2Raw.hpp index 0dfdedb..2a75e05 100644 --- a/include/ChaiVM/utils/instr2Raw.hpp +++ b/include/ChaiVM/utils/instr2Raw.hpp @@ -16,4 +16,6 @@ chai::bytecode_t instr2Raw(Operation op, Immidiate imm); chai::bytecode_t instr2Raw(Operation op); +chai::bytecode_t inst2RawRI(Operation op, RegisterId r1, Immidiate imm); + } // namespace chai::utils diff --git a/src/ChaiVM/interpreter/decoder.cpp b/src/ChaiVM/interpreter/decoder.cpp index 85b10e3..aa9f59d 100644 --- a/src/ChaiVM/interpreter/decoder.cpp +++ b/src/ChaiVM/interpreter/decoder.cpp @@ -6,7 +6,7 @@ namespace chai::interpreter::decoder { Instruction parse(bytecode_t word) { const Opcode opcode = utils::ExtractBits(word); - assert(opcode <= IcCos); + assert(opcode <= Goto); return Instruction{ .operation = static_cast(opcode), .immidiate = utils::ExtractBits(word), diff --git a/src/ChaiVM/interpreter/executor.cpp b/src/ChaiVM/interpreter/executor.cpp index 13c7bc6..f561eed 100644 --- a/src/ChaiVM/interpreter/executor.cpp +++ b/src/ChaiVM/interpreter/executor.cpp @@ -8,7 +8,7 @@ namespace chai::interpreter { #define DO_NEXT_INS() \ Instruction newIns = \ decoder::parse(codeManager_->getBytecode(regFile_.pc())); \ - (this->*handlerArr[newIns.operation])(newIns); + (this->*HANDLER_ARR[newIns.operation])(newIns); Executor::Executor(CodeManager *manager) : codeManager_(manager), regFile_(codeManager_->startPC()) {} @@ -191,6 +191,91 @@ void Executor::iccos(Instruction ins) { advancePc(); DO_NEXT_INS() } +void Executor::if_icmpeq(Instruction ins) { + if (regFile_.acc() == regFile_[ins.r1]) { + static_assert(sizeof(Immidiate) == sizeof(int16_t)); + regFile_.pc() += static_cast(ins.immidiate); + } else { + advancePc(); + } + DO_NEXT_INS() +} +void Executor::if_icmpne(Instruction ins) { + if (regFile_.acc() != regFile_[ins.r1]) { + regFile_.pc() += static_cast(ins.immidiate); + } else { + advancePc(); + } + DO_NEXT_INS() +} +void Executor::if_icmpgt(Instruction ins) { + if (regFile_.acc() > regFile_[ins.r1]) { + regFile_.pc() += static_cast(ins.immidiate); + } else { + advancePc(); + } + DO_NEXT_INS() +} +void Executor::if_icmpge(Instruction ins) { + if (regFile_.acc() >= regFile_[ins.r1]) { + regFile_.pc() += static_cast(ins.immidiate); + } else { + advancePc(); + } + DO_NEXT_INS() +} +void Executor::if_icmplt(Instruction ins) { + if (regFile_.acc() < regFile_[ins.r1]) { + regFile_.pc() += static_cast(ins.immidiate); + } else { + advancePc(); + } + DO_NEXT_INS() +} +void Executor::if_icmple(Instruction ins) { + if (regFile_.acc() <= regFile_[ins.r1]) { + regFile_.pc() += static_cast(ins.immidiate); + } else { + advancePc(); + } + DO_NEXT_INS() +} +void Executor::if_acmpeq(Instruction ins) { + /* + * @todo #42:90min Implement the instruction with object ref + * when objects will be introduced in chai. + */ + DO_NEXT_INS() +} +void Executor::if_acmpne(Instruction ins) { + /* + * @todo #42:90min Implement the instruction with object ref + * when chai objects will be introduced. + */ + DO_NEXT_INS() +} +void Executor::cmpgf(Instruction ins) { + double acc_f64 = std::bit_cast(regFile_.acc()); + double r1_f64 = std::bit_cast(regFile_[ins.r1]); + regFile_.acc() = (acc_f64 >= r1_f64) + ? static_cast(acc_f64 != r1_f64) + : static_cast(-1); + advancePc(); + DO_NEXT_INS() +} +void Executor::cmplf(Instruction ins) { + double acc_f64 = std::bit_cast(regFile_.acc()); + double r1_f64 = std::bit_cast(regFile_[ins.r1]); + regFile_.acc() = regFile_.acc() = + (acc_f64 <= r1_f64) ? static_cast(acc_f64 != r1_f64) + : static_cast(-1); + advancePc(); + DO_NEXT_INS() +} +void Executor::g0t0(Instruction ins) { + regFile_.pc() += static_cast(ins.immidiate); + DO_NEXT_INS() +} InvalidInstruction::InvalidInstruction(const char *msg) : runtime_error(msg) {} InvalidInstruction::InvalidInstruction(const std::string &msg) diff --git a/src/ChaiVM/utils/instr2Raw.cpp b/src/ChaiVM/utils/instr2Raw.cpp index 24fed4a..f635224 100644 --- a/src/ChaiVM/utils/instr2Raw.cpp +++ b/src/ChaiVM/utils/instr2Raw.cpp @@ -18,4 +18,9 @@ chai::bytecode_t instr2Raw(Operation op, Immidiate imm) { chai::bytecode_t instr2Raw(Operation op) { return (operation2opcode(op)); } +chai::bytecode_t inst2RawRI(Operation op, RegisterId r1, Immidiate imm) { + return (operation2opcode(op)) | (static_cast(imm) << 16) | + (r1 << 8); +} + } // namespace chai::utils diff --git a/test/ChaiVM/interpreter/executor_test.cpp b/test/ChaiVM/interpreter/executor_test.cpp index 79fcfed..d66a5ac 100644 --- a/test/ChaiVM/interpreter/executor_test.cpp +++ b/test/ChaiVM/interpreter/executor_test.cpp @@ -6,15 +6,40 @@ #include "ChaiVM/utils/constant.hpp" #include "ChaiVM/utils/instr2Raw.hpp" -using namespace chai::interpreter; -using namespace chai::utils; +using chai::bytecode_t; +using chai::utils::inst2RawRI; +using chai::utils::instr2Raw; class ExecutorTest : public ::testing::Test { protected: + static constexpr RegisterId R0 = 1; + static constexpr RegisterId R1 = 1; + static constexpr RegisterId R2 = 2; + static constexpr RegisterId R3 = 3; + static constexpr RegisterId R4 = 4; + static constexpr RegisterId R5 = 5; + static constexpr RegisterId R6 = 6; + static constexpr RegisterId R7 = 7; + static constexpr RegisterId R8 = 8; + static constexpr RegisterId R9 = 9; + static constexpr RegisterId R10 = 10; + static constexpr RegisterId R11 = 11; + const std::filesystem::path PATH{"./exec-testing.chai"}; - void load(Operation op, RegisterId r1, RegisterId r2) { - chaiFile_.addInstr(instr2Raw(op, r1, r2)); + /* + * @todo #42:60min Rename all load methods to more appropriate names. + */ + void loadRR(Operation op, RegisterId reg1, RegisterId reg2 = 0) { + chaiFile_.addInstr(instr2Raw(op, reg1, reg2)); + } + + void loadRI(Operation op, RegisterId reg1, Immidiate imm) { + chaiFile_.addInstr(inst2RawRI(op, reg1, imm)); + } + + int loadI(Operation op, Immidiate imm) { + return chaiFile_.addInstr(instr2Raw(op, imm)); } void loadWithConst(Operation op, int64_t data) { @@ -25,7 +50,7 @@ class ExecutorTest : public ::testing::Test { chaiFile_.addWithConst(op, data); } - void load(Operation op) { chaiFile_.addInstr(instr2Raw(op)); } + int load(Operation op) { return chaiFile_.addInstr(instr2Raw(op)); } void update() { chaiFile_.toFile(PATH); @@ -53,12 +78,12 @@ class MathTest : public ExecutorTest {}; */ TEST_F(ExecutorTest, run) { loadWithConst(Ldia, static_cast(6)); - load(Star, 2, 0); + loadRR(Star, 2, 0); loadWithConst(Ldia, static_cast(8)); - load(Star, 3, 0); - load(Ldra, 3, 0); - load(Mul, 2, 0); - load(Ret, 0, 0); + loadRR(Star, 3, 0); + loadRR(Ldra, 3, 0); + loadRR(Mul, 2, 0); + loadRR(Ret, 0, 0); update(); exec_.run(); @@ -88,8 +113,8 @@ TEST_F(ExecutorTest, mov) { RegisterId r1 = 0; RegisterId r2 = 1; loadWithConst(Ldia, val); - load(Star, r1, 0); - load(Mov, r1, r2); + loadRR(Star, r1, 0); + loadRR(Mov, r1, r2); load(Ret); update(); exec_.run(); @@ -110,8 +135,8 @@ TEST_F(ExecutorTest, ldra) { int64_t val = -3L; RegisterId r1 = 0; loadWithConst(Ldia, val); - load(Star, r1, 0); - load(Ldra, r1, 0); + loadRR(Star, r1, 0); + loadRR(Ldra, r1, 0); load(Ret); update(); exec_.run(); @@ -124,7 +149,7 @@ TEST_F(ExecutorTest, star) { int64_t val = 3L; RegisterId r1 = 0; loadWithConst(Ldia, val); - load(Star, r1, 0); + loadRR(Star, r1, 0); load(Ret); update(); exec_.run(); @@ -135,15 +160,14 @@ TEST_F(ExecutorTest, star) { TEST_F(ExecutorTest, add) { int64_t val1 = 10; int64_t val2 = 33; - RegisterId r1 = 0; loadWithConst(Ldia, val1); - load(Star, r1, 0); + loadRR(Star, R1, 0); loadWithConst(Ldia, val2); - load(Add, r1, 0); + loadRR(Add, R1, 0); load(Ret); update(); exec_.run(); - EXPECT_EQ(exec_.getState()[r1], val1); + EXPECT_EQ(exec_.getState()[R1], val1); EXPECT_EQ(static_cast(exec_.getState().acc()), val1 + val2); EXPECT_EQ(exec_.getState().pc(), sizeof(chai::bytecode_t) * 5); } @@ -152,9 +176,9 @@ TEST_F(ExecutorTest, addNeg) { int64_t val2 = -33; RegisterId r1 = 0; loadWithConst(Ldia, val1); - load(Star, r1, 0); + loadRR(Star, r1, 0); loadWithConst(Ldia, val2); - load(Add, r1, 0); + loadRR(Add, r1, 0); load(Ret); update(); exec_.run(); @@ -178,9 +202,9 @@ TEST_F(ExecutorTest, sub) { int64_t val2 = 33; RegisterId r1 = 0; loadWithConst(Ldia, val1); - load(Star, r1, 0); + loadRR(Star, r1, 0); loadWithConst(Ldia, val2); - load(Sub, r1, 0); + loadRR(Sub, r1, 0); load(Ret); update(); exec_.run(); @@ -204,9 +228,9 @@ TEST_F(ExecutorTest, mul) { int64_t val2 = -33; RegisterId r1 = 0; loadWithConst(Ldia, val1); - load(Star, r1, 0); + loadRR(Star, r1, 0); loadWithConst(Ldia, val2); - load(Mul, r1, 0); + loadRR(Mul, r1, 0); load(Ret); update(); exec_.run(); @@ -230,9 +254,9 @@ TEST_F(ExecutorTest, div) { int64_t val2 = -33; RegisterId r1 = 1; loadWithConst(Ldia, val1); - load(Star, r1, 0); + loadRR(Star, r1, 0); loadWithConst(Ldia, val2); - load(Div, r1, 0); + loadRR(Div, r1, 0); load(Ret); update(); exec_.run(); @@ -265,9 +289,9 @@ TEST_F(ExecutorTest, addf) { auto val2 = 2.71; RegisterId r1 = 0; loadWithConst(Ldiaf, val1); - load(Star, r1, 0); + loadRR(Star, r1, 0); loadWithConst(Ldiaf, val2); - load(Addf, r1, 0); + loadRR(Addf, r1, 0); load(Ret); update(); exec_.run(); @@ -289,15 +313,14 @@ TEST_F(ExecutorTest, addif) { TEST_F(ExecutorTest, subf) { auto val1 = 3.14; auto val2 = 2.71; - RegisterId r = 0; loadWithConst(Ldiaf, val1); - load(Star, r, 0); + loadRR(Star, R0, 0); loadWithConst(Ldiaf, val2); - load(Subf, r, 0); + loadRR(Subf, R0, 0); load(Ret); update(); exec_.run(); - EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[r]), val1); + EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[R0]), val1); EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState().acc()), val2 - val1); EXPECT_EQ(exec_.getState().pc(), sizeof(chai::bytecode_t) * 5); } @@ -317,9 +340,9 @@ TEST_F(ExecutorTest, mulf) { auto val2 = 2.71; RegisterId r1 = 0; loadWithConst(Ldiaf, val1); - load(Star, r1, 0); + loadRR(Star, r1, 0); loadWithConst(Ldiaf, val2); - load(Mulf, r1, 0); + loadRR(Mulf, r1, 0); load(Ret); update(); exec_.run(); @@ -341,15 +364,14 @@ TEST_F(ExecutorTest, mulif) { TEST_F(ExecutorTest, divf) { auto val1 = 3.14; auto val2 = 2.71; - RegisterId r = 0; loadWithConst(Ldiaf, val2); - load(Star, r, 0); + loadRR(Star, R0, 0); loadWithConst(Ldiaf, val1); - load(Divf, r, 0); + loadRR(Divf, R0, 0); load(Ret); update(); exec_.run(); - EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[r]), val2); + EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[R0]), val2); EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState().acc()), val1 / val2); EXPECT_EQ(exec_.getState().pc(), sizeof(chai::bytecode_t) * 5); } @@ -396,72 +418,255 @@ TEST_F(MathTest, iccos) { } TEST_F(ExecutorTest, SquareEquation) { - const RegisterId r1 = 1; - const RegisterId r2 = 2; - const RegisterId r3 = 3; - const RegisterId r4 = 4; - const RegisterId r5 = 5; - const RegisterId r6 = 6; - const RegisterId r7 = 7; - const RegisterId r8 = 8; - const RegisterId r9 = 9; - const RegisterId r10 = 10; - const RegisterId r11 = 11; // r1 = 1.0, r2 = -5.0, r3 = 6.0 loadWithConst(Ldiaf, 1.0); - load(Star, r1, 0); + loadRR(Star, R1, 0); loadWithConst(Ldiaf, -5.0); - load(Star, r2, 0); + loadRR(Star, R2, 0); loadWithConst(Ldiaf, +6.0); - load(Star, r3, 0); + loadRR(Star, R3, 0); // r4 = -4*r1*r3 loadWithConst(Ldiaf, -4.0); - load(Mulf, r1, 0); - load(Mulf, r3, 0); - load(Star, r4, 0); + loadRR(Mulf, R1, 0); + loadRR(Mulf, R3, 0); + loadRR(Star, R4, 0); // r5 = b * b - load(Ldra, r2, 0); - load(Mulf, r2, 0); - load(Star, r5, 0); + loadRR(Ldra, R2, 0); + loadRR(Mulf, R2, 0); + loadRR(Star, R5, 0); // r6 = r5 + r4 - load(Ldra, r5, 0); - load(Addf, r4, 0); - load(Star, r6, 0); + loadRR(Ldra, R5, 0); + loadRR(Addf, R4, 0); + loadRR(Star, R6, 0); // r6 = sqrt(r6) - load(Ldra, r6, 0); + loadRR(Ldra, R6, 0); load(IcSqrt); - load(Star, r6, 0); + loadRR(Star, R6, 0); // r7 = 2a - load(Ldra, r1, 0); + loadRR(Ldra, R1, 0); loadWithConst(Mulif, 2.0); - load(Star, r7, 0); + loadRR(Star, R7, 0); // r8 = r6 - r2 - load(Ldra, r6, 0); - load(Subf, r2, 0); - load(Star, r8, 0); + loadRR(Ldra, R6, 0); + loadRR(Subf, R2, 0); + loadRR(Star, R8, 0); // X1 = r9 = r8 / r7 - load(Ldra, r8, 0); - load(Divf, r7, 0); - load(Star, r9, 0); + loadRR(Ldra, R8, 0); + loadRR(Divf, R7, 0); + loadRR(Star, R9, 0); // acc = -r2 - r6 // r11 = acc / r7 loadWithConst(Ldiaf, 0.0); - load(Subf, r2, 0); - load(Subf, r6, 0); - load(Divf, r7, 0); - load(Star, r11, 0); + loadRR(Subf, R2, 0); + loadRR(Subf, R6, 0); + loadRR(Divf, R7, 0); + loadRR(Star, R11, 0); load(Ret); update(); exec_.run(); - EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[r9]), 3.0); - EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[r11]), 2.0); + EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[R9]), 3.0); + EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState()[R11]), 2.0); EXPECT_FLOAT_EQ(std::bit_cast(exec_.getState().acc()), 2.0); } + +TEST_F(ExecutorTest, If_icmpeq_simple) { + Immidiate val = chaiFile_.addConst(std::make_unique(42)); + loadI(Ldia, val); + loadRR(Star, R1); + loadRI(If_icmpeq, R1, 2 * sizeof(bytecode_t)); + load(Inv); + load(Ret); + update(); + exec_.run(); +} + +TEST_F(ExecutorTest, If_icmpne_cycle) { + constexpr int64_t threshold = 2000; + loadWithConst(Ldia, static_cast(1)); + loadRR(Star, R1); + loadWithConst(Ldia, threshold); + loadRR(Star, R10); + loadWithConst(Ldia, static_cast(0)); + loadRR(Add, R1); + loadRI(If_icmpne, R10, static_cast(-1 * sizeof(bytecode_t))); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), threshold); +} + +TEST_F(ExecutorTest, If_icmpgt_cycle) { + constexpr int64_t threshold = -200; + loadWithConst(Ldia, static_cast(1)); + loadRR(Star, R1); + loadWithConst(Ldia, threshold); + loadRR(Star, R10); + loadWithConst(Ldia, static_cast(0)); + loadRR(Sub, R1); + loadRI(If_icmpgt, R10, static_cast(-1 * sizeof(bytecode_t))); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), threshold); +} + +TEST_F(ExecutorTest, If_icmpge_cycle) { + constexpr int64_t threshold = -200; + loadWithConst(Ldia, static_cast(1)); + loadRR(Star, R1); + loadWithConst(Ldia, threshold); + loadRR(Star, R10); + loadWithConst(Ldia, static_cast(0)); + loadRR(Sub, R1); + loadRI(If_icmpge, R10, static_cast(-1 * sizeof(bytecode_t))); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), threshold - 1); +} + +TEST_F(ExecutorTest, If_icmplt_cycle) { + constexpr int64_t threshold = 200; + loadWithConst(Ldia, static_cast(1)); + loadRR(Star, R1); + loadWithConst(Ldia, threshold); + loadRR(Star, R10); + loadWithConst(Ldia, static_cast(0)); + loadRR(Add, R1); + loadRI(If_icmplt, R10, static_cast(-1 * sizeof(bytecode_t))); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), threshold); +} + +TEST_F(ExecutorTest, If_icmple_cycle) { + constexpr int64_t threshold = 200; + loadWithConst(Ldia, static_cast(1)); + loadRR(Star, R1); + loadWithConst(Ldia, threshold); + loadRR(Star, R10); + loadWithConst(Ldia, static_cast(0)); + loadRR(Add, R1); + loadRI(If_icmple, R10, static_cast(-1 * sizeof(bytecode_t))); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), threshold + 1); +} + +TEST_F(ExecutorTest, Cmpgf_greater) { + loadWithConst(Ldiaf, 0.1234567); + loadRR(Star, R1); + loadWithConst(Ldiaf, 123.9); + // acc > r1 + loadRR(Сmpgf, R1); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), 1); +} + +TEST_F(ExecutorTest, Cmpgf_less) { + loadWithConst(Ldiaf, 0.1234567); + loadRR(Star, R1); + loadWithConst(Ldiaf, -123.9); + // acc < r1 + loadRR(Сmpgf, R1); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), -1); +} + +TEST_F(ExecutorTest, Cmpgf_equal) { + loadWithConst(Ldiaf, 0.123456789); + loadRR(Star, R1); + loadWithConst(Ldiaf, 0.123456789); + // acc < r1 + loadRR(Сmpgf, R1); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), 0); +} + +TEST_F(ExecutorTest, Cmpgf_nan) { + loadWithConst(Ldiaf, NAN); + loadRR(Star, R1); + loadWithConst(Ldiaf, 0.123456789); + // r1 is NaN + loadRR(Сmpgf, R1); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), -1); +} + +TEST_F(ExecutorTest, Cmplf_less) { + loadWithConst(Ldiaf, 0.15); + loadRR(Star, R1); + loadWithConst(Ldiaf, -1234.5); + // acc < r1 + loadRR(Cmplf, R1); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), 1); +} + +TEST_F(ExecutorTest, Cmplf_nan) { + loadWithConst(Ldiaf, 0.15); + loadRR(Star, R1); + loadWithConst(Ldiaf, NAN); + // acc is NaN + loadRR(Cmplf, R1); + load(Ret); + update(); + exec_.run(); + EXPECT_EQ(exec_.getState().acc(), -1); +} + +TEST_F(ExecutorTest, Goto_forward) { + constexpr int ret = 345; + loadI(Goto, (ret) * sizeof(bytecode_t)); + for (int i = 0; i < ret - 1; ++i) { + load(Inv); + } + ASSERT_EQ(load(Ret), ret); + for (int i = 0; i < 500; ++i) { + load(Inv); + } + update(); + exec_.run(); +} + +TEST_F(ExecutorTest, Goto_forward_and_back) { + // jump to + constexpr int ret1 = 345; + constexpr int ret2 = ret1 + 5; + loadI(Goto, (ret2) * sizeof(bytecode_t)); + for (int i = 0; i < ret1 - 1; ++i) { + load(Inv); + } + ASSERT_EQ(load(Ret), ret1); + load(Inv); + load(Inv); + load(Inv); + load(Inv); + ASSERT_EQ(loadI(Goto, static_cast(-5 * sizeof(bytecode_t))), + ret2); + for (int i = 0; i < 500; ++i) { + load(Inv); + } + update(); + exec_.run(); +} diff --git a/tools/resources/instructions.yml b/tools/resources/instructions.yml index 82a8b37..73a38c9 100644 --- a/tools/resources/instructions.yml +++ b/tools/resources/instructions.yml @@ -127,3 +127,48 @@ instructions: fixedvalue: 29 mnemonic: IcCos format: N + - + fixedvalue: 30 + mnemonic: If_icmpeq + format: N + - + fixedvalue: 31 + mnemonic: If_icmpne + format: RI + - + fixedvalue: 32 + mnemonic: If_icmpgt + format: RI + - + fixedvalue: 33 + mnemonic: If_icmpge + format: RI + - + fixedvalue: 34 + mnemonic: If_icmplt + format: RI + - + fixedvalue: 35 + mnemonic: If_icmple + format: RI + + - + fixedvalue: 36 + mnemonic: If_acmpeq + format: RI + - + fixedvalue: 37 + mnemonic: If_acmpne + format: RI + - + fixedvalue: 38 + mnemonic: Сmpgf + format: R + - + fixedvalue: 39 + mnemonic: Cmplf + format: R + - + fixedvalue: 40 + mnemonic: Goto + format: I