Skip to content

Commit

Permalink
Changing function call logic in CodeManager and Assembler (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
c71n93 authored Jun 10, 2024
1 parent 9619217 commit f885ea3
Show file tree
Hide file tree
Showing 20 changed files with 308 additions and 186 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ jobs:

- name: Test
working-directory: ${{github.workspace}}/build
run: ctest --test-dir ${{github.workspace}}/build/test
run: ctest --test-dir ${{github.workspace}}/build/test --output-on-failure
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ build: init

.PHONY: test
test: build
export GTEST_COLOR=1 && ctest --test-dir $(PWD)/$(BUILD_DIR)/test --parallel $(JOBS) --output-on-failure
export GTEST_COLOR=1 && ctest --test-dir $(PWD)/$(BUILD_DIR)/test --parallel $(JOBS) --output-on-failure

.PHONY: execute-tests-inside-make
execute-tests-inside-make:
Expand Down
9 changes: 1 addition & 8 deletions include/ChaiVM/interpreter/code-manager/code-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class CodeManager final {

chsize_t getCnst(Immidiate id);

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

Immidiate addCnstString(std::string &&str) {
stringPool_.emplace_back(str);
Expand Down Expand Up @@ -70,13 +70,6 @@ class CodeManager final {
* here.
*/
std::vector<std::string> stringPool_;

/**
* Id in appropriate collection by immidiate.
* For example, func by imm is found as funcs_[dispatch_[imm]].
* @todo #1:90min We can avoid using dispatch_ anywhere via inheritance.
*/
std::vector<Immidiate> dispatch_;
};

class BeyondCodeBoundaries : public std::runtime_error {
Expand Down
6 changes: 3 additions & 3 deletions include/ChaiVM/utils/instr2Raw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ chai::bytecode_t instr2Raw(interpreter::Operation op,

chai::bytecode_t instr2Raw(interpreter::Operation op);

chai::bytecode_t inst2RawRI(interpreter::Operation op,
interpreter::RegisterId r1,
interpreter::Immidiate imm);
chai::bytecode_t instr2RawRI(interpreter::Operation op,
interpreter::RegisterId r1,
interpreter::Immidiate imm);

} // namespace chai::utils
32 changes: 32 additions & 0 deletions include/ChaiVM/utils/io-bytes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <fstream>

namespace chai::utils {

/**
* Writes bytes of data of a given type from a given address to a given output
* stream.
*
* @tparam T type of data.
* @param os output stream.
* @param pdata pointer to data.
*/
template <typename T> void writeBytes(std::ostream &os, const T *pdata) {
os.write(reinterpret_cast<const char *>(pdata), sizeof(T));
}

/**
* Reads bytes of data of a given type from a given output stream.
*
* @tparam T type of data.
* @param is input stream.
* @return
*/
template <typename T> T readBytes(std::istream &is) {
T data;
is.read(reinterpret_cast<char *>(&data), sizeof(T));
return data;
}

} // namespace chai::utils
10 changes: 10 additions & 0 deletions include/frontend/assembler/asmlex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class AsmLex final : public yyFlexLexer {
OP_CURLY_BRACKET,
CL_CURLY_BRACKET,
COMMA,
EOF_,
UNKNOWN
};

Expand Down Expand Up @@ -77,6 +78,11 @@ class AsmLex final : public yyFlexLexer {
Comma() : Lexem(LexemType::COMMA) {}
~Comma() override {}
};
class Eof final : public Lexem {
public:
Eof(LexemType t) : Lexem(t) {}
~Eof() override {}
};
class Unknown final : public Lexem {
public:
Unknown() : Lexem(LexemType::UNKNOWN) {}
Expand Down Expand Up @@ -131,6 +137,10 @@ class AsmLex final : public yyFlexLexer {
LexemType::STRING, withQuotes.substr(1, withQuotes.size() - 2));
return 0;
}
int processEOF() {
currentLexem_ = std::make_unique<Eof>(LexemType::EOF_);
return 0;
}
int processUnknown() {
currentLexem_ = std::make_unique<Unknown>();
return 1;
Expand Down
155 changes: 107 additions & 48 deletions include/frontend/assembler/assembler.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include <sstream>
#include <unordered_map>
#include <utility>

#include "ChaiVM/interpreter/autogen/operations.hpp"
#include "ChaiVM/utils/file-format/chai-file.hpp"
Expand All @@ -25,11 +27,32 @@ class Assembler final {
lex_.switch_streams(&inputFile_);
}

void collectFunstions() {
uint16_t func_id = 0;
while (lex_.nextLexem()->type != AsmLex::EOF_) {
if (lex_.currentLexem()->type == AsmLex::FUNC) {
func_id++;
expectNextLexem(AsmLex::IDENTIFIER, "Expected function name");
std::string func_name = dynamic_cast<AsmLex::Identifier *>(
lex_.currentLexem().get())
->value;
funcsIdByName_.insert({func_name, func_id});
}
}
inputFile_.seekg(0);
lex_.yyrestart(inputFile_);
}

/*
* @todo #41:90min Implement adequate processing of the main function
*/
void assemble() {
collectFunstions();
processMain();
while (lex_.currentLexem()->type != AsmLex::EOF_) {
processFunction();
lex_.nextLexem();
}
chaiFile_.toFile(outPath_);
}

Expand All @@ -38,34 +61,61 @@ class Assembler final {
chai::utils::fileformat::ChaiFile chaiFile_;
std::ifstream inputFile_;
std::filesystem::path outPath_;
std::unordered_map<std::string, uint16_t> funcsIdByName_;

/*
* @todo #41:90min Refactor this function. Or maybe it is better to kill
* myself?
*/
void processMain() {
lex_.nextLexem();
checkError();
while (lex_.currentLexem()->type == AsmLex::IDENTIFIER) {
checkError();
chaiFile_.addInstr(processInstruction());
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::IDENTIFIER &&
SmartOperation(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value) == chai::interpreter::Ret) {
chaiFile_.addInstr(processInstruction());
break;
}
}
}
/*
* @todo #76:90min Add function description to assembler
*/
/*
* @todo #76:90min Add function to constant pool before parsing instructions
* (for recursion)
*/
void processFunction() {
expectCurrentLexem(AsmLex::FUNC, "Expected function declaration");
expectNextLexem(AsmLex::IDENTIFIER, "Expected function name");
std::string func_name =
dynamic_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value;
expectNextLexem(AsmLex::INTEGER,
"Expected number of registers in function frame");
auto num_regs = static_cast<uint8_t>(
dynamic_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
expectNextLexem(AsmLex::INTEGER,
"Expected number of function arguments");
auto num_args = static_cast<uint8_t>(
dynamic_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
expectNextLexem(AsmLex::OP_CURLY_BRACKET,
"Expected opening curly bracket");
std::vector<chai::bytecode_t> instrs;
lex_.nextLexem();
while (lex_.currentLexem()->type != AsmLex::CL_CURLY_BRACKET) {
instrs.push_back(processInstruction());
lex_.nextLexem();
}
expectCurrentLexem(AsmLex::CL_CURLY_BRACKET,
"Expected closing curly bracket");
chaiFile_.addFunction(UINT16_MAX, func_name, "V(V)", instrs, num_args,
num_regs);
}
chai::bytecode_t processInstruction() {
SmartOperation op = SmartOperation(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
dynamic_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
if (op == chai::interpreter::Inv) {
throw AssembleError("Invalid instruction", lex_.lineno());
}
if (op == chai::interpreter::Call) {
return processCall(op);
}
switch (op.format()) {
case chai::interpreter::N:
return processN(op);
Expand All @@ -85,6 +135,12 @@ class Assembler final {
break;
}
}
chai::bytecode_t processCall(chai::interpreter::Operation op) {
auto func_name = static_cast<std::string>(
dynamic_cast<AsmLex::Identifier *>(lex_.nextLexem().get())->value);
uint16_t func_id = funcsIdByName_[func_name];
return chai::utils::instr2RawRI(op, func_id, func_id);
}
chai::bytecode_t processN(chai::interpreter::Operation op) {
return chai::utils::instr2Raw(op, 0, 0);
}
Expand All @@ -94,69 +150,69 @@ class Assembler final {
}
chai::bytecode_t processRR(chai::interpreter::Operation op) {
chai::interpreter::RegisterId reg1Id = processReg();
expectComma();
expectNextLexem(AsmLex::COMMA, "Expected coma");
chai::interpreter::RegisterId reg2Id = processReg();
return chai::utils::instr2Raw(op, reg1Id, reg2Id);
}
chai::bytecode_t processI(chai::interpreter::Operation op) {
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::INTEGER) {
return chaiFile_.getWithConst(
op, static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())
->value));
auto val = static_cast<int64_t>(
dynamic_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstI64>(val));
return chai::utils::instr2Raw(op, imm);
} else if (lex_.currentLexem()->type == AsmLex::FLOAT) {
return chaiFile_.getWithConst(
op, (static_cast<AsmLex::Float *>(lex_.currentLexem().get())
->value));
auto val =
dynamic_cast<AsmLex::Float *>(lex_.currentLexem().get())->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstF64>(val));
return chai::utils::instr2Raw(op, imm);
} else if (lex_.currentLexem()->type == AsmLex::STRING) {
std::string str =
static_cast<AsmLex::String *>(lex_.currentLexem().get())->value;
dynamic_cast<AsmLex::String *>(lex_.currentLexem().get())
->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstRawStr>(str));
auto bytecode = chai::utils::instr2Raw(op, imm);
chaiFile_.addInstr(bytecode);
return bytecode;
return chai::utils::instr2Raw(op, imm);
} else {
throw AssembleError("Unknown instruction type in ProcessI",
lex_.lineno());
}
}
chai::bytecode_t processRI(chai::interpreter::Operation op) {
chai::interpreter::RegisterId regId = processReg();
expectComma();
expectNextLexem(AsmLex::COMMA, "Expected coma");
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::INTEGER) {
return chai::utils::inst2RawRI(
op, regId,
static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())
->value));
auto val = static_cast<int64_t>(
dynamic_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstI64>(val));
return chai::utils::instr2RawRI(op, regId, imm);
} else if (lex_.currentLexem()->type == AsmLex::FLOAT) {
return chai::utils::inst2RawRI(
op, regId,
static_cast<AsmLex::Float *>(lex_.currentLexem().get())->value);
auto val =
dynamic_cast<AsmLex::Float *>(lex_.currentLexem().get())->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstI64>(val));
return chai::utils::instr2RawRI(op, regId, imm);
} else if (lex_.currentLexem()->type == AsmLex::STRING) {
std::string str =
static_cast<AsmLex::String *>(lex_.currentLexem().get())->value;
dynamic_cast<AsmLex::String *>(lex_.currentLexem().get())
->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstRawStr>(str));
auto bytecode = chai::utils::inst2RawRI(op, regId, imm);
chaiFile_.addInstr(bytecode);
return bytecode;
return chai::utils::instr2RawRI(op, regId, imm);
} else {
throw AssembleError("Unknown instruction type in processRI",
lex_.lineno());
}
}

chai::interpreter::RegisterId processReg() {
lex_.nextLexem();
if (lex_.currentLexem()->type != AsmLex::IDENTIFIER) {
throw AssembleError("Expected register", lex_.lineno());
}
expectNextLexem(AsmLex::IDENTIFIER, "Expected register name");
return regNameToRegId(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
dynamic_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
}

Expand All @@ -165,20 +221,23 @@ class Assembler final {
throw AssembleError("Unknown lexem", lex_.lineno());
}
}
void expectComma() {
void expectNextLexem(AsmLex::LexemType type, std::string msg) {
lex_.nextLexem();
if (lex_.currentLexem()->type != AsmLex::COMMA) {
throw AssembleError("Expected comma", lex_.lineno());
if (lex_.currentLexem()->type != type) {
throw AssembleError(std::move(msg), lex_.lineno());
}
}
void expectCurrentLexem(AsmLex::LexemType type, std::string msg) {
if (lex_.currentLexem()->type != type) {
throw AssembleError(std::move(msg), lex_.lineno());
}
}
chai::interpreter::RegisterId regNameToRegId(std::string regName) {
chai::interpreter::RegisterId regId;
if (regName.length() > 1 && regName[0] == 'r') {
std::string digits = regName.substr(1);
regId = std::stoi(digits);
std::istringstream iss(digits);
if (!(iss >> regId)) {
throw AssembleError("Invalid register number", lex_.lineno());
}
} else {
throw AssembleError("Invalid register format", lex_.lineno());
}
Expand Down
Loading

5 comments on commit f885ea3

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on f885ea3 Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 1-083ca17e disappeared from include/ChaiVM/interpreter/code-manager/code-manager.hpp), that's why I closed #63. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on f885ea3 Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 41-4dc1c56c disappeared from include/frontend/assembler/assembler.hpp), that's why I closed #71. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on f885ea3 Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 76-b32f7d66 discovered in include/frontend/assembler/assembler.hpp) and submitted as #90. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on f885ea3 Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 76-5ab331a4 discovered in include/frontend/assembler/assembler.hpp) and submitted as #91. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on f885ea3 Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 87-19a57d9f discovered in src/ChaiVM/interpreter/code-manager/code-manager.cpp) and submitted as #92. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.