Skip to content

Commit

Permalink
refactor(vm)!: moving instructions and padding so that we have inst(8…
Browse files Browse the repository at this point in the history
…)-padding(8)-arg(16), to be able to handle instructions with two arguments, using the padding along arg
  • Loading branch information
SuperFola committed Oct 6, 2024
1 parent e77cfbe commit 28100c4
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 47 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
- the `STORE` instruction has been renamed `SET_VAL`
- the `STORE` instruction is emitted in place of the `LET` and `MUT` instructions, without any mutability checking now
- `io:writeFile` no longer takes a mode and has been split into `io:writeFile` and `io:appendToFile`
- instructions are now positioned like this: `inst byte1 byte2 byte3`
- byte1 is 0 if the instruction takes a single argument on 16 bits, split on byte2 and byte3
- if the instruction takes two arguments, they each have 12 bits ; the first one is on byte1 and upper half of byte2, the second on lower half of byte2 and then byte3

### Removed
- removed unused `NodeType::Closure`
Expand Down
13 changes: 0 additions & 13 deletions include/Ark/Compiler/Compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,6 @@ namespace Ark::internal
return m_temp_pages[page.index];
}

/**
* @brief helper functions to get a temp or finalized code page
*
* @param page page descriptor
* @return std::vector<IR::Block>*
*/
IR::Block* page_ptr(const Page page) noexcept
{
if (!page.is_temp)
return &m_code_pages[page.index];
return &m_temp_pages[page.index];
}

/**
* @brief Checking if a symbol is an operator
*
Expand Down
7 changes: 5 additions & 2 deletions include/Ark/Compiler/IntermediateRepresentation/Entity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ namespace Ark::internal::IR
Goto,
GotoIfTrue,
GotoIfFalse,
Opcode
Opcode,
Opcode2Args
};

using label_t = std::size_t;
Expand All @@ -38,6 +39,8 @@ namespace Ark::internal::IR

explicit Entity(Instruction inst, uint16_t arg = 0);

Entity(Instruction inst, uint16_t primary_arg, uint16_t secondary_arg);

static Entity Label();

static Entity Goto(const Entity& label);
Expand All @@ -56,8 +59,8 @@ namespace Ark::internal::IR
Kind m_kind;
label_t m_label { 0 };
Instruction m_inst;
uint8_t m_secondary_arg { 0 };
uint16_t m_primary_arg { 0 };
uint16_t m_secondary_arg { 0 };
};

using Block = std::vector<Entity>;
Expand Down
31 changes: 16 additions & 15 deletions include/Ark/Compiler/Word.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,29 @@

namespace Ark::internal
{
struct bytes_t
{
uint8_t first {};
uint8_t second {};
};

struct Word
{
uint8_t padding = 0; ///< Padding reserved for future use
uint8_t opcode = 0; ///< Instruction opcode
uint16_t data = 0; ///< Immediate data, interpreted differently for different instructions
uint8_t opcode = 0; ///< Instruction opcode
uint8_t byte_1 = 0;
uint8_t byte_2 = 0;
uint8_t byte_3 = 0;

explicit Word(const uint8_t inst, const uint16_t arg = 0) :
opcode(inst), data(arg)
opcode(inst), byte_2(static_cast<uint8_t>(arg >> 8)), byte_3(static_cast<uint8_t>(arg & 0xff))
{}

[[nodiscard]] bytes_t bytes() const
/**
* @brief Construct a word with two arguments, each on 12 bits. It's up to the caller to ensure that no data is lost
* @param inst
* @param primary_arg argument on 12 bits, the upper 4 bits are lost
* @param secondary_arg 2nd argument on 12 bits, the upper 4 bits are lost
*/
Word(const uint8_t inst, const uint16_t primary_arg, const uint16_t secondary_arg) :
opcode(inst)
{
return bytes_t {
.first = static_cast<uint8_t>((data & 0xff00) >> 8),
.second = static_cast<uint8_t>(data & 0x00ff)
};
byte_1 = static_cast<uint8_t>((primary_arg & 0xff0) >> 4);
byte_2 = static_cast<uint8_t>((primary_arg & 0x00f) << 4 | (secondary_arg & 0xf00) >> 8);
byte_3 = static_cast<uint8_t>(secondary_arg & 0x0ff);
}
};
}
Expand Down
3 changes: 1 addition & 2 deletions include/Ark/VM/VM.inl
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,7 @@ inline void VM::call(internal::ExecutionContext& context, const uint16_t argc)
needed_argc = 0;

// every argument is a MUT declaration in the bytecode
// index+1 to skip the padding
while (m_state.m_pages[context.pp][index + 1] == STORE)
while (m_state.m_pages[context.pp][index] == STORE)
{
needed_argc += 1;
index += 4; // instructions are on 4 bytes
Expand Down
7 changes: 4 additions & 3 deletions src/arkreactor/Compiler/BytecodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,14 +392,15 @@ namespace Ark

for (std::size_t j = sStart.value_or(0), end = sEnd.value_or(page.size()); j < end; j += 4)
{
const uint8_t padding = page[j];
const uint8_t inst = page[j + 1];
const uint8_t inst = page[j];
// TEMP
const uint8_t padding = page[j + 1];
const auto arg = static_cast<uint16_t>((page[j + 2] << 8) + page[j + 3]);

// instruction number
fmt::print(fmt::fg(fmt::color::cyan), "{:>4}", j / 4);
// padding inst arg arg
fmt::print(" {:02x} {:02x} {:02x} {:02x} ", padding, inst, page[j + 2], page[j + 3]);
fmt::print(" {:02x} {:02x} {:02x} {:02x} ", inst, padding, page[j + 2], page[j + 3]);

if (inst == NOP)
color_print_inst("NOP");
Expand Down
12 changes: 10 additions & 2 deletions src/arkreactor/Compiler/IntermediateRepresentation/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ namespace Ark::internal::IR
m_inst(inst), m_primary_arg(arg)
{}

Entity::Entity(const Instruction inst, const uint16_t primary_arg, const uint16_t secondary_arg) :
m_kind(Kind::Opcode2Args),
m_inst(inst), m_primary_arg(primary_arg), m_secondary_arg(secondary_arg)
{}

Entity Entity::Label()
{
auto label = Entity(Kind::Label);
Expand All @@ -38,7 +43,10 @@ namespace Ark::internal::IR

Word Entity::bytecode() const
{
// todo: handle secondary_arg
return Word(m_inst, m_primary_arg + m_secondary_arg);
if (m_kind == Kind::Opcode)
return Word(m_inst, m_primary_arg);
if (m_kind == Kind::Opcode2Args)
return Word(m_inst, m_primary_arg, m_secondary_arg);
return Word(0, 0);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <Ark/Compiler/IntermediateRepresentation/IRCompiler.hpp>

#include <chrono>
#include <utility>
#include <unordered_map>
#include <picosha2.h>

Expand Down Expand Up @@ -103,6 +104,8 @@ namespace Ark::internal
break;

case IR::Kind::Opcode:
[[fallthrough]];
case IR::Kind::Opcode2Args:
pushWord(inst.bytecode());
break;

Expand All @@ -115,12 +118,10 @@ namespace Ark::internal

void IRCompiler::pushWord(const Word& word)
{
m_bytecode.push_back(word.padding);
m_bytecode.push_back(word.opcode);

auto [first, second] = word.bytes();
m_bytecode.push_back(first);
m_bytecode.push_back(second);
m_bytecode.push_back(word.byte_1);
m_bytecode.push_back(word.byte_2);
m_bytecode.push_back(word.byte_3);
}

void IRCompiler::pushFileHeader() noexcept
Expand Down
9 changes: 4 additions & 5 deletions src/arkreactor/VM/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ namespace Ark
#define NEXTOPARG() \
do \
{ \
padding = m_state.m_pages[context.pp][context.ip]; \
inst = m_state.m_pages[context.pp][context.ip + 1]; \
inst = m_state.m_pages[context.pp][context.ip]; \
padding = m_state.m_pages[context.pp][context.ip + 1]; \
arg = static_cast<uint16_t>((m_state.m_pages[context.pp][context.ip + 2] << 8) + \
m_state.m_pages[context.pp][context.ip + 3]); \
context.ip += 4; \
Expand Down Expand Up @@ -564,9 +564,8 @@ namespace Ark

if (Value* field = var->refClosure().refScope()[arg]; field != nullptr)
{
// check for CALL instruction
// doing a +1 on the IP to read the instruction because context.ip is already on the next instruction word (the padding)
if (context.ip + 1 < m_state.m_pages[context.pp].size() && m_state.m_pages[context.pp][context.ip + 1] == CALL)
// check for CALL instruction (the instruction because context.ip is already on the next instruction word)
if (m_state.m_pages[context.pp][context.ip] == CALL)
push(Value(Closure(var->refClosure().scopePtr(), field->pageAddr())), context);
else
push(field, context);
Expand Down
27 changes: 27 additions & 0 deletions tests/unittests/CompilerSuite.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <boost/ut.hpp>

#include <Ark/Compiler/Word.hpp>

using namespace boost;

ut::suite<"Compiler"> compiler_suite = [] {
using namespace ut;

"Word construction"_test = [] {
should("create a word with a single argument on 2 bytes") = [] {
const auto word = Ark::internal::Word(12, 0x5678);
expect(that % word.opcode == 12);
expect(that % word.byte_1 == 0);
expect(that % word.byte_2 == 0x56);
expect(that % word.byte_3 == 0x78);
};

should("split arguments evenly between 3 bytes") = [] {
const auto word = Ark::internal::Word(12, 0x0567, 0x089a);
expect(that % word.opcode == 12);
expect(that % word.byte_1 == 0x56);
expect(that % word.byte_2 == 0x78);
expect(that % word.byte_3 == 0x9a);
};
};
};

0 comments on commit 28100c4

Please sign in to comment.