Skip to content

Commit

Permalink
#65: Implemented Arrays and Strings
Browse files Browse the repository at this point in the history
Co-authored-by: Roman Korostinskiy <[email protected]>
  • Loading branch information
levBagryansky and c71n93 authored Dec 19, 2023
1 parent 853ab23 commit 0de8229
Show file tree
Hide file tree
Showing 10 changed files with 426 additions and 17 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ add_custom_target(gen_operations_header
COMMENT "Generating ${OPERATIONS_DIR}"
OUTPUT ${OPERATIONS_DIR}
COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/opcode2operation-generator.py ${OPERATIONS_DIR} ${CMAKE_SOURCE_DIR}/tools/resources/instructions.yml
)
)

add_library(chai_include INTERFACE)
add_dependencies(chai_include gen_operations_header)
Expand Down
10 changes: 10 additions & 0 deletions ISA.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ There is ChaiVM's accumulator(acc) based ISA.
| Cmplf | R | f64 -> i64, compare acc with r1. Acc became 1 i64 if less than r1, 0 if equal, otherwise -1 |
| Goto | I | Goes to another instruction at branchoffset [imm] |
| Call | I | Calls function [imm]. Imm is reference to function in constant pool named constant_func_name_and_type. |
| NewI64Array | N | Allocates array of type i64 with number of elements from acc register. A reference to this new array is stored in acc. |
| GetI64FromArr | R | Gets i64 from i64 array in acc and puts it to acc. |
| SetI64InArr | RR | Sets i64 value to i64 array in acc and puts it to acc. |
| NewF64Array | N | Allocates array of type f64 with number of elements from acc register. A reference to this new array is stored in acc. |
| GetF64FromArr | R | Gets f64 from f64 array in acc and puts it to acc. |
| SetF64InArr | RR | Sets f64 value to f64 array in acc and puts it to acc. |
| StringPrint | N | Prints String in acc |
| StringConcat | R | Create new String, concatenating String in acc and String in r1. Result in acc. |
| StringLen | N | Puts len of String to acc |
| StringSlice | RR | Create new String slicing String placed in acc. r1 is start and r2 is finish of slicing |

To generate this file use the following python script:
```shell
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ func_info {
u1[] code // Instructions, byte array.
}
```

## Strings
All strings are contained in CodeManager.stringPool_. Some of them initialized with starting of VM but you also can create own string in runtime via `StringConcat` or `StringSlice` instructions.
7 changes: 7 additions & 0 deletions include/ChaiVM/interpreter/code-manager/code-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ class CodeManager final {

chsize_t getCnst(Immidiate id);

const std::string &getCnstString(Immidiate id) { return stringPool_[id]; }

Immidiate addCnstString(std::string &&str) {
stringPool_.emplace_back(str);
return stringPool_.size() - 1;
}

bytecode_t getBytecode(size_t func, chsize_t pc);

const Function &getFunc(Immidiate imm) const;
Expand Down
77 changes: 62 additions & 15 deletions include/ChaiVM/interpreter/executor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,69 @@ class Executor {
void cmplf(Instruction ins);
void g0t0(Instruction ins);
void call(Instruction ins);
void newi64array(Instruction ins);
void get_i64from_arr(Instruction ins);
void set_i64in_arr(Instruction ins);
void newf64array(Instruction ins);
void get_f64from_arr(Instruction ins);
void set_f64in_arr(Instruction ins);
void string_print(Instruction ins);
void string_concat(Instruction ins);
void string_len(Instruction ins);
void string_slice(Instruction ins);

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, &Executor::call};
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,
&Executor::call,
&Executor::newi64array,
&Executor::get_i64from_arr,
&Executor::set_i64in_arr,
&Executor::newf64array,
&Executor::get_f64from_arr,
&Executor::set_f64in_arr,
&Executor::string_print,
&Executor::string_concat,
&Executor::string_len,
&Executor::string_slice};

private:
chsize_t acc_;
Expand Down
2 changes: 1 addition & 1 deletion src/ChaiVM/interpreter/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace chai::interpreter::decoder {

Instruction parse(bytecode_t word) {
const Opcode opcode = utils::ExtractBits<bytecode_t, 8, 0>(word);
assert(opcode <= Call);
// assert(opcode <= NewF64Array);
return Instruction{
.operation = static_cast<Operation>(opcode),
.immidiate = utils::ExtractBits<bytecode_t, Immidiate, 16, 16>(word),
Expand Down
80 changes: 80 additions & 0 deletions src/ChaiVM/interpreter/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,86 @@ void Executor::call(Instruction ins) {
pc() = 0;
DO_NEXT_INS();
}
void Executor::newi64array(Instruction ins) {
int n = static_cast<int64_t>(acc());
memory::LinearAllocator<int64_t> allocator{buffer_};
assert(n >= 0);
auto *arr = new (allocator.allocate(n)) int64_t[n]();
acc() = reinterpret_cast<chsize_t>(arr);
advancePc();
DO_NEXT_INS();
}
void Executor::get_i64from_arr(Instruction ins) {
int i = static_cast<int64_t>((*currentFrame_)[ins.r1]);
auto *arr = reinterpret_cast<int64_t *>(acc());
acc() = arr[i];
advancePc();
DO_NEXT_INS();
}

void Executor::set_i64in_arr(Instruction ins) {
int i = static_cast<int64_t>((*currentFrame_)[ins.r1]);
auto *arr = reinterpret_cast<int64_t *>(acc());
arr[i] = static_cast<int64_t>((*currentFrame_)[ins.r2]);
advancePc();
DO_NEXT_INS();
}

void Executor::newf64array(Instruction ins) {
int n = static_cast<int64_t>(acc());
memory::LinearAllocator<double> allocator{buffer_};
assert(n >= 0);
auto *arr = new (allocator.allocate(n)) double[n]();
acc() = reinterpret_cast<chsize_t>(arr);
advancePc();
DO_NEXT_INS();
}
void Executor::get_f64from_arr(Instruction ins) {
int i = static_cast<int64_t>((*currentFrame_)[ins.r1]);
auto *arr = reinterpret_cast<double *>(acc());
acc() = std::bit_cast<int64_t>(arr[i]);
advancePc();
DO_NEXT_INS();
}

void Executor::set_f64in_arr(Instruction ins) {
int i = static_cast<int64_t>((*currentFrame_)[ins.r1]);
auto *arr = reinterpret_cast<double *>(acc());
arr[i] = std::bit_cast<double>((*currentFrame_)[ins.r2]);
advancePc();
DO_NEXT_INS();
}

void Executor::string_print(Instruction ins) {
const std::string &str = codeManager_->getCnstString(acc());
std::cout << str;
advancePc();
DO_NEXT_INS();
}

void Executor::string_concat(Instruction ins) {
const std::string &str1 = codeManager_->getCnstString(acc());
const std::string &str2 =
codeManager_->getCnstString((*currentFrame_)[ins.r1]);
std::string concated = str1 + str2;
acc() = codeManager_->addCnstString(std::move(concated));
advancePc();
DO_NEXT_INS();
}

void Executor::string_len(Instruction ins) {
acc() = codeManager_->getCnstString(acc()).size();
advancePc();
DO_NEXT_INS();
}
void Executor::string_slice(Instruction ins) {
const std::string &str = codeManager_->getCnstString(acc());
acc() = codeManager_->addCnstString(
str.substr((*currentFrame_)[ins.r1],
(*currentFrame_)[ins.r2] - (*currentFrame_)[ins.r1]));
advancePc();
DO_NEXT_INS();
}

InvalidInstruction::InvalidInstruction(const char *msg) : runtime_error(msg) {}
InvalidInstruction::InvalidInstruction(const std::string &msg)
Expand Down
151 changes: 151 additions & 0 deletions test/ChaiVM/interpreter/executor_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,154 @@ TEST_F(ExecutorTest, Call) {
EXPECT_EQ(static_cast<int64_t>(exec_.acc()), val2 - val1);
EXPECT_EQ(exec_.getCurrentFrame(), nullptr);
}

/*
* r3 = 23
* acc = 100
* i64[] acc = new i64[acc]
* acc = acc[r3]
*/
TEST_F(ExecutorTest, GetI64FromArr) {
constexpr auto i = static_cast<int64_t>(23);
constexpr auto size = static_cast<int64_t>(50);
loadWithConst(Ldia, i);
loadRR(Star, R3);
loadWithConst(Ldia, size);
load(NewI64Array);
loadRR(GetI64FromArr, R3);
load(Ret);
update();
exec_.run();
EXPECT_EQ(static_cast<int64_t>(exec_.acc()), 0);
EXPECT_EQ(exec_.getCurrentFrame(), nullptr);
}

/*
* r3 = 23 //i
* r4 = 12345
* acc = 100
* i64[] acc = new i64[acc]
* acc = acc[r3]
*/
TEST_F(ExecutorTest, SetI64SetArr) {
constexpr auto i = static_cast<int64_t>(23);
constexpr auto size = static_cast<int64_t>(50);
constexpr auto value = static_cast<int64_t>(12345);
loadWithConst(Ldia, i);
loadRR(Star, R3);
loadWithConst(Ldia, value);
loadRR(Star, R4);
loadWithConst(Ldia, size);
load(NewI64Array);
loadRR(SetI64InArr, R3, R4);
loadRR(GetI64FromArr, R3);
load(Ret);
update();
exec_.run();
EXPECT_EQ(static_cast<int64_t>(exec_.acc()), value);
EXPECT_EQ(exec_.getCurrentFrame(), nullptr);
}

/*
* r3 = 23
* acc = 100
* i64[] acc = new а64[acc]
* acc = acc[r3]
* acc == 0.0?
*/
TEST_F(ExecutorTest, GetF64FromArr) {
constexpr auto i = static_cast<int64_t>(23);
constexpr auto size = static_cast<int64_t>(50);
loadWithConst(Ldia, i);
loadRR(Star, R3);
loadWithConst(Ldia, size);
load(NewF64Array);
loadRR(GetF64FromArr, R3);
load(Ret);
update();
exec_.run();
EXPECT_EQ(static_cast<int64_t>(exec_.acc()), 0.0);
EXPECT_EQ(exec_.getCurrentFrame(), nullptr);
}

/*
* r3 = 23 //i
* r4 = 12.345
* acc = 100
* i64[] acc = new f64[acc]
* acc = acc[r3]
*/
TEST_F(ExecutorTest, SetF64SetArr) {
constexpr auto i = static_cast<int64_t>(23);
constexpr auto size = static_cast<int64_t>(50);
constexpr auto value = static_cast<double>(12.345);
loadWithConst(Ldia, i);
loadRR(Star, R3);
loadWithConst(Ldiaf, value);
loadRR(Star, R4);
loadWithConst(Ldia, size);
load(NewF64Array);
loadRR(SetF64InArr, R3, R4);
loadRR(GetF64FromArr, R3);
load(Ret);
update();
exec_.run();
EXPECT_EQ(std::bit_cast<double>(exec_.acc()), value);
EXPECT_EQ(exec_.getCurrentFrame(), nullptr);
}

TEST_F(ExecutorTest, StringPrint) {
Immidiate raw = chaiFile_.addConst(std::make_unique<ConstRawStr>("ABOBA"));
loadI(Ldia, raw);
load(StringPrint);
load(Ret);
update();
exec_.run();
EXPECT_EQ(codeManager_.getCnstString(exec_.acc()), "ABOBA");
EXPECT_EQ(codeManager_.getCnstString(codeManager_.getCnst(raw)), "ABOBA");
}

TEST_F(ExecutorTest, StringConcat) {
Immidiate raw1 = chaiFile_.addConst(std::make_unique<ConstRawStr>("ABOBA"));
Immidiate raw2 =
chaiFile_.addConst(std::make_unique<ConstRawStr>(" Yeash"));
loadI(Ldia, raw2);
loadRR(Star, R2);
load(StringPrint);
loadI(Ldia, raw1);
load(StringPrint);
loadRR(StringConcat, R2);
load(Ret);
update();
exec_.run();
EXPECT_EQ(codeManager_.getCnstString(exec_.acc()), "ABOBA Yeash");
EXPECT_EQ(codeManager_.getCnstString(codeManager_.getCnst(raw1)), "ABOBA");
}

TEST_F(ExecutorTest, StringSize) {
Immidiate raw = chaiFile_.addConst(std::make_unique<ConstRawStr>("ABOBA"));
loadI(Ldia, raw);
load(StringLen);
load(Ret);
update();
exec_.run();
EXPECT_EQ(exec_.acc(), 5);
}

TEST_F(ExecutorTest, StringSlice) {
Immidiate raw = chaiFile_.addConst(std::make_unique<ConstRawStr>("ABOBA"));
constexpr auto start = static_cast<int64_t>(1);
constexpr auto end = static_cast<int64_t>(4);
loadWithConst(Ldia, start);
loadRR(Star, R2);
loadWithConst(Ldia, end);
loadRR(Star, R3);
loadI(Ldia, raw);
load(chai::interpreter::StringPrint);
loadRR(StringSlice, R2, R3);
load(Ret);
update();
exec_.run();
EXPECT_EQ(codeManager_.getCnstString(exec_.acc()), "BOB");
EXPECT_EQ(codeManager_.getCnstString(codeManager_.getCnst(raw)), "ABOBA");
}
Loading

0 comments on commit 0de8229

Please sign in to comment.