From db6ff8deba8086d154ad60af3ef91b00a1eb355d Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Sat, 10 Aug 2024 18:24:16 +0100 Subject: [PATCH] Add "Opcode" type --- CMakeLists.txt | 1 + src/arena.cpp | 14 ++++++++++++ src/arena.hpp | 1 + src/common.cpp | 4 ++++ src/common.hpp | 43 +++++++++++++++++++++++++++++++++++ src/compiler.cpp | 40 ++++++++++++++++++++++++++++---- src/compiler.hpp | 1 + src/opcode.hpp | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pod.hpp | 13 +++++++++++ src/vli.cpp | 2 +- src/writer.cpp | 6 +++++ src/writer.hpp | 1 + 12 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 src/opcode.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 17ccdf2..ad21dcf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ target_sources(vm_lib src/writer.hpp src/utf8.hpp src/compiler.hpp + src/opcode.hpp ) add_executable(vli src/vli.cpp) diff --git a/src/arena.cpp b/src/arena.cpp index e89aeae..848ef1d 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -79,6 +79,8 @@ Result Arena::gc_pod(PodObject* obj) { return gc_bytearray((PodByteArray*)obj); case Tag::Dict: return gc_dict((PodDict*)obj); + case Tag::Opcode: + return gc_opcode((PodOpcode*)obj); } return ERROR(TypeMismatch); @@ -178,6 +180,18 @@ Result Arena::gc_dict(PodDict* obj) { return nobj; } +Result Arena::gc_opcode(PodOpcode* obj) { + auto nobj = TRY(alloc()); + nobj->header.tag = Tag::Opcode; + nobj->opcode = obj->opcode; + nobj->arg1 = obj->arg1; + nobj->arg2 = obj->arg2; + nobj->arg3 = obj->arg3; + nobj->arg4 = obj->arg4; + + return nobj; +} + Arena& get_arena() { if (current_arena == 0) die("Arena not set\n"); return *current_arena; diff --git a/src/arena.hpp b/src/arena.hpp index 98fac15..800831b 100644 --- a/src/arena.hpp +++ b/src/arena.hpp @@ -154,6 +154,7 @@ class Arena { Result gc_array(PodArray* obj); Result gc_bytearray(PodByteArray* obj); Result gc_dict(PodDict* obj); + Result gc_opcode(PodOpcode* obj); void add_root(GcRootList* node) { _gcroot.insert(node); } diff --git a/src/common.cpp b/src/common.cpp index 9a39bfd..cea7659 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -36,6 +36,8 @@ Result Value::create(PodObject* obj) { return Value(TRY(Syntax::create((PodSyntax*)obj))); case Tag::Pair: return Value(TRY(Pair::create((PodPair*)obj))); + case Tag::Opcode: + return Value(TRY(Opcode::create((PodOpcode*)obj))); }; return Value(); } @@ -101,6 +103,8 @@ Result Pair::copy() const { return Value(Pair(TRY(_value.copy()))); } Result Bool::copy() const { return Value(Bool(TRY(_value.copy()))); } +Result Opcode::copy() const { return Value(Opcode(TRY(_value.copy()))); } + Result Pair::create(Value& first, Value& rest) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Pair; diff --git a/src/common.hpp b/src/common.hpp index a328767..1b41a8d 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -7,6 +7,7 @@ #include "arena.hpp" #include "error.hpp" +#include "opcode.hpp" #include "pod.hpp" #include "utf8.hpp" @@ -699,6 +700,48 @@ class Bool : public Object { GcRoot _value; }; +class Opcode : public Object { + public: + Opcode() {} + Opcode(Opcode&& rhs) : _value(std::move(rhs._value)) {} + Opcode(GcRoot&& val) : _value(std::move(val)) {} + + virtual Tag tag() final { return Tag::Opcode; } + virtual PodObject* pod() final { return _value.get(); } + virtual Result cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); } + virtual Result cmp(Opcode& rhs) final { return 0; } + + virtual void move(Object* obj) final { new (obj) Opcode(std::move(_value)); } + + static Result create(PodOpcode* obj) { + return Opcode(TRY(MkGcRoot(obj))); + } + + static Result create(Oc opcode, OpArg arg1 = {0, 0}, + OpArg arg2 = {0, 0}, OpArg arg3 = {0, 0}, + OpArg arg4 = {0, 0}) { + auto pod = TRY(arena_alloc()); + pod->header.tag = Tag::Opcode; + pod->opcode = opcode; + pod->arg1 = arg1; + pod->arg2 = arg2; + pod->arg3 = arg3; + pod->arg4 = arg4; + + return Opcode(TRY(MkGcRoot(pod))); + } + + Oc opcode() { return _value->opcode; } + OpArg arg1() { return _value->arg1; } + OpArg arg2() { return _value->arg2; } + OpArg arg3() { return _value->arg3; } + OpArg arg4() { return _value->arg4; } + + virtual Result copy() const final; + + private: + GcRoot _value; +}; // note: this class doesn't perform proper destruction of objects in some cases class Value { public: diff --git a/src/compiler.cpp b/src/compiler.cpp index b130079..da1bb1b 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -15,12 +15,25 @@ struct Context { return Context(std::move(env), std::move(constants)); } + uint64_t alloc_reg() { + uint64_t reg = maxreg; + ++maxreg; + return reg; + } + Value env; Array constants; uint64_t maxreg; uint64_t maxconst; }; +Result add_opcode(Array& opcodes, Oc opcode, OpArg arg1 = {0, 0}, + OpArg arg2 = {0, 0}, OpArg arg3 = {0, 0}, + OpArg arg4 = {0, 0}) { + Value oc = Value(TRY(Opcode::create(opcode, arg1, arg2, arg3, arg4))); + return opcodes.append(oc); +} + Result is_primitive_op(Symbol& sym) { return TRY(sym.cmp("+")) == 0 || TRY(sym.cmp("-")) == 0 || TRY(sym.cmp("*")) == 0 || TRY(sym.cmp("/")) == 0; @@ -37,9 +50,10 @@ Result Compiler::compile_expr(Context& context, Value& expr) { switch (expr.tag()) { case Tag::Pair: return compile_list(context, *expr.to()); + case Tag::Int64: + return compile_int64(context, *expr.to()); case Tag::Nil: case Tag::Bool: - case Tag::Int64: case Tag::Float: case Tag::String: case Tag::Symbol: @@ -47,6 +61,7 @@ Result Compiler::compile_expr(Context& context, Value& expr) { case Tag::Array: case Tag::ByteArray: case Tag::Dict: + case Tag::Opcode: return ERROR(TypeMismatch); } return ERROR(TypeMismatch); @@ -54,21 +69,30 @@ Result Compiler::compile_expr(Context& context, Value& expr) { Result Compiler::compile_primop(Context& context, Symbol& op, Pair& expr) { - std::cout << "primop\n"; - Value cur = TRY(expr.rest()); Array code = TRY(Array::create()); + uint64_t reg = context.alloc_reg(); + std::cout << "load-immediate r" << reg << ", " << 0 << "\n"; + code = TRY(add_opcode(code, Oc::LoadImmediate, {0, (int64_t)reg}, {0, 0})); + while (!cur.is()) { Pair& pair = *cur.to(); auto subexpr = TRY(pair.first()); auto comp = TRY(compile_expr(context, subexpr)); + uint64_t res = context.alloc_reg(); + std::cout << "add r" << res << ", r" << reg << ", r" << comp.reg << "\n"; + + reg = res; cur = TRY(pair.rest()); } - return ERROR(TypeMismatch); + + Expression ex = Expression(reg, TRY(Array::create())); + return ex; } + Result Compiler::compile_list(Context& context, Pair& expr) { auto first = TRY(expr.first()); @@ -80,3 +104,11 @@ Result Compiler::compile_list(Context& context, Pair& expr) { } return ERROR(TypeMismatch); } + +Result Compiler::compile_int64(Context& context, Int64& value) { + uint64_t reg = context.alloc_reg(); + std::cout << "loadc r" << reg << ", " << value.value() << "\n"; + + Expression expr = Expression(reg, TRY(Array::create())); + return expr; +} diff --git a/src/compiler.hpp b/src/compiler.hpp index 5591bec..ef85def 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -19,4 +19,5 @@ class Compiler { Result compile_expr(Context& context, Value& expr); Result compile_list(Context& context, Pair& expr); Result compile_primop(Context& context, Symbol& op, Pair& expr); + Result compile_int64(Context& context, Int64& value); }; diff --git a/src/opcode.hpp b/src/opcode.hpp new file mode 100644 index 0000000..6175aa5 --- /dev/null +++ b/src/opcode.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include + +enum class Oc : uint8_t { + Unknown = 0, + Add, + Sub, + Mul, + Div, + Mod, + Mov, + LoadImmediate, + // constants + LoadConst, + // Load/store + LoadStack, + // Jumps + Jump, + JumpEqual, + JumpLess, + JumpLessEqual, + JumpNotEqual, + // Function calls + Call, + TailCall, + // Return from function call + Ret, + RetNil, + // Shifts + ShiftRight, + ShiftLeft, + // Bitwise + BitwiseAnd, + BitwiseOr, + BitwiseXor, + BitwiseNeg, + // Arrays + MakeArray, + ArrayLoad, + ArrayStore, + // Stack + Push, + Pop, + StackReserve, + // Assert + AssertEqual, + // Dictionaries + MakeDict, + SetJump, + // Globals + SetGlobal, + GetGlobal, +}; + +struct OpArg { + uint8_t is_const : 1 = 0; + int64_t arg : 63 = 0; +}; diff --git a/src/pod.hpp b/src/pod.hpp index fcd5277..9d193a4 100644 --- a/src/pod.hpp +++ b/src/pod.hpp @@ -2,6 +2,7 @@ #include +#include "opcode.hpp" #include "result.hpp" #include "sourcerange.hpp" @@ -17,6 +18,7 @@ enum class Tag : uint8_t { Array, ByteArray, Dict, + Opcode, }; template @@ -142,6 +144,17 @@ class PodPair : public PodObject { OffPtr rest; }; +class PodOpcode final : public PodObject { + public: + PodOpcode() : PodObject(Tag::Opcode){}; + + Oc opcode; + OpArg arg1; + OpArg arg2; + OpArg arg3; + OpArg arg4; +}; + template class Ptr { public: diff --git a/src/vli.cpp b/src/vli.cpp index ec9c06d..706828c 100644 --- a/src/vli.cpp +++ b/src/vli.cpp @@ -9,7 +9,7 @@ StaticArena<64 * 1024 * 1024> arena; int main() { - auto s = DIEX(String::create("(+ 1 2 3)")); + auto s = DIEX(String::create("(+ (+ 1 2 3) 4)")); auto reader = Reader(s); auto r = DIEX(reader.read_one()); diff --git a/src/writer.cpp b/src/writer.cpp index 027c00b..2521dcd 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -24,6 +24,8 @@ Result Writer::write_one(Value& obj) { return write_syntax(*obj.to()); case Tag::Pair: return write_pair(*obj.to()); + case Tag::Opcode: + return write_opcode(*obj.to()); }; return String(); } @@ -212,6 +214,10 @@ Result Writer::write_dict(Dict& val) { return res; } +Result Writer::write_opcode(Opcode& val) { + return ERROR(NotImplemented); +} + Result write_one(Value& value) { auto w = Writer(); return w.write_one(value); diff --git a/src/writer.hpp b/src/writer.hpp index e857723..c0630ea 100644 --- a/src/writer.hpp +++ b/src/writer.hpp @@ -22,6 +22,7 @@ class Writer { Result write_dict(Dict& val); Result write_symbol(Symbol& val); Result write_syntax(Syntax& val); + Result write_opcode(Opcode& val); }; Result write_one(Value& value);