Add "Opcode" type
This commit is contained in:
parent
935c629460
commit
db6ff8deba
12 changed files with 180 additions and 5 deletions
|
@ -35,6 +35,7 @@ target_sources(vm_lib
|
||||||
src/writer.hpp
|
src/writer.hpp
|
||||||
src/utf8.hpp
|
src/utf8.hpp
|
||||||
src/compiler.hpp
|
src/compiler.hpp
|
||||||
|
src/opcode.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(vli src/vli.cpp)
|
add_executable(vli src/vli.cpp)
|
||||||
|
|
|
@ -79,6 +79,8 @@ Result<PodObject*> Arena::gc_pod(PodObject* obj) {
|
||||||
return gc_bytearray((PodByteArray*)obj);
|
return gc_bytearray((PodByteArray*)obj);
|
||||||
case Tag::Dict:
|
case Tag::Dict:
|
||||||
return gc_dict((PodDict*)obj);
|
return gc_dict((PodDict*)obj);
|
||||||
|
case Tag::Opcode:
|
||||||
|
return gc_opcode((PodOpcode*)obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR(TypeMismatch);
|
return ERROR(TypeMismatch);
|
||||||
|
@ -178,6 +180,18 @@ Result<PodObject*> Arena::gc_dict(PodDict* obj) {
|
||||||
return nobj;
|
return nobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<PodObject*> Arena::gc_opcode(PodOpcode* obj) {
|
||||||
|
auto nobj = TRY(alloc<PodOpcode>());
|
||||||
|
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() {
|
Arena& get_arena() {
|
||||||
if (current_arena == 0) die("Arena not set\n");
|
if (current_arena == 0) die("Arena not set\n");
|
||||||
return *current_arena;
|
return *current_arena;
|
||||||
|
|
|
@ -154,6 +154,7 @@ class Arena {
|
||||||
Result<PodObject*> gc_array(PodArray* obj);
|
Result<PodObject*> gc_array(PodArray* obj);
|
||||||
Result<PodObject*> gc_bytearray(PodByteArray* obj);
|
Result<PodObject*> gc_bytearray(PodByteArray* obj);
|
||||||
Result<PodObject*> gc_dict(PodDict* obj);
|
Result<PodObject*> gc_dict(PodDict* obj);
|
||||||
|
Result<PodObject*> gc_opcode(PodOpcode* obj);
|
||||||
|
|
||||||
void add_root(GcRootList* node) { _gcroot.insert(node); }
|
void add_root(GcRootList* node) { _gcroot.insert(node); }
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ Result<Value> Value::create(PodObject* obj) {
|
||||||
return Value(TRY(Syntax::create((PodSyntax*)obj)));
|
return Value(TRY(Syntax::create((PodSyntax*)obj)));
|
||||||
case Tag::Pair:
|
case Tag::Pair:
|
||||||
return Value(TRY(Pair::create((PodPair*)obj)));
|
return Value(TRY(Pair::create((PodPair*)obj)));
|
||||||
|
case Tag::Opcode:
|
||||||
|
return Value(TRY(Opcode::create((PodOpcode*)obj)));
|
||||||
};
|
};
|
||||||
return Value();
|
return Value();
|
||||||
}
|
}
|
||||||
|
@ -101,6 +103,8 @@ Result<Value> Pair::copy() const { return Value(Pair(TRY(_value.copy()))); }
|
||||||
|
|
||||||
Result<Value> Bool::copy() const { return Value(Bool(TRY(_value.copy()))); }
|
Result<Value> Bool::copy() const { return Value(Bool(TRY(_value.copy()))); }
|
||||||
|
|
||||||
|
Result<Value> Opcode::copy() const { return Value(Opcode(TRY(_value.copy()))); }
|
||||||
|
|
||||||
Result<Pair> Pair::create(Value& first, Value& rest) {
|
Result<Pair> Pair::create(Value& first, Value& rest) {
|
||||||
auto pod = TRY(arena_alloc<PodPair>());
|
auto pod = TRY(arena_alloc<PodPair>());
|
||||||
pod->header.tag = Tag::Pair;
|
pod->header.tag = Tag::Pair;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "arena.hpp"
|
#include "arena.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "opcode.hpp"
|
||||||
#include "pod.hpp"
|
#include "pod.hpp"
|
||||||
#include "utf8.hpp"
|
#include "utf8.hpp"
|
||||||
|
|
||||||
|
@ -699,6 +700,48 @@ class Bool : public Object {
|
||||||
GcRoot<PodBool> _value;
|
GcRoot<PodBool> _value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Opcode : public Object {
|
||||||
|
public:
|
||||||
|
Opcode() {}
|
||||||
|
Opcode(Opcode&& rhs) : _value(std::move(rhs._value)) {}
|
||||||
|
Opcode(GcRoot<PodOpcode>&& val) : _value(std::move(val)) {}
|
||||||
|
|
||||||
|
virtual Tag tag() final { return Tag::Opcode; }
|
||||||
|
virtual PodObject* pod() final { return _value.get(); }
|
||||||
|
virtual Result<short> cmp(Object& rhs) final { return -TRY(rhs.cmp(*this)); }
|
||||||
|
virtual Result<short> cmp(Opcode& rhs) final { return 0; }
|
||||||
|
|
||||||
|
virtual void move(Object* obj) final { new (obj) Opcode(std::move(_value)); }
|
||||||
|
|
||||||
|
static Result<Opcode> create(PodOpcode* obj) {
|
||||||
|
return Opcode(TRY(MkGcRoot(obj)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<Opcode> create(Oc opcode, OpArg arg1 = {0, 0},
|
||||||
|
OpArg arg2 = {0, 0}, OpArg arg3 = {0, 0},
|
||||||
|
OpArg arg4 = {0, 0}) {
|
||||||
|
auto pod = TRY(arena_alloc<PodOpcode>());
|
||||||
|
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<Value> copy() const final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GcRoot<PodOpcode> _value;
|
||||||
|
};
|
||||||
// note: this class doesn't perform proper destruction of objects in some cases
|
// note: this class doesn't perform proper destruction of objects in some cases
|
||||||
class Value {
|
class Value {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -15,12 +15,25 @@ struct Context {
|
||||||
return Context(std::move(env), std::move(constants));
|
return Context(std::move(env), std::move(constants));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t alloc_reg() {
|
||||||
|
uint64_t reg = maxreg;
|
||||||
|
++maxreg;
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
Value env;
|
Value env;
|
||||||
Array constants;
|
Array constants;
|
||||||
uint64_t maxreg;
|
uint64_t maxreg;
|
||||||
uint64_t maxconst;
|
uint64_t maxconst;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Result<Array> 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<bool> is_primitive_op(Symbol& sym) {
|
Result<bool> is_primitive_op(Symbol& sym) {
|
||||||
return TRY(sym.cmp("+")) == 0 || TRY(sym.cmp("-")) == 0 ||
|
return TRY(sym.cmp("+")) == 0 || TRY(sym.cmp("-")) == 0 ||
|
||||||
TRY(sym.cmp("*")) == 0 || TRY(sym.cmp("/")) == 0;
|
TRY(sym.cmp("*")) == 0 || TRY(sym.cmp("/")) == 0;
|
||||||
|
@ -37,9 +50,10 @@ Result<Expression> Compiler::compile_expr(Context& context, Value& expr) {
|
||||||
switch (expr.tag()) {
|
switch (expr.tag()) {
|
||||||
case Tag::Pair:
|
case Tag::Pair:
|
||||||
return compile_list(context, *expr.to<Pair>());
|
return compile_list(context, *expr.to<Pair>());
|
||||||
|
case Tag::Int64:
|
||||||
|
return compile_int64(context, *expr.to<Int64>());
|
||||||
case Tag::Nil:
|
case Tag::Nil:
|
||||||
case Tag::Bool:
|
case Tag::Bool:
|
||||||
case Tag::Int64:
|
|
||||||
case Tag::Float:
|
case Tag::Float:
|
||||||
case Tag::String:
|
case Tag::String:
|
||||||
case Tag::Symbol:
|
case Tag::Symbol:
|
||||||
|
@ -47,6 +61,7 @@ Result<Expression> Compiler::compile_expr(Context& context, Value& expr) {
|
||||||
case Tag::Array:
|
case Tag::Array:
|
||||||
case Tag::ByteArray:
|
case Tag::ByteArray:
|
||||||
case Tag::Dict:
|
case Tag::Dict:
|
||||||
|
case Tag::Opcode:
|
||||||
return ERROR(TypeMismatch);
|
return ERROR(TypeMismatch);
|
||||||
}
|
}
|
||||||
return ERROR(TypeMismatch);
|
return ERROR(TypeMismatch);
|
||||||
|
@ -54,21 +69,30 @@ Result<Expression> Compiler::compile_expr(Context& context, Value& expr) {
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
||||||
Pair& expr) {
|
Pair& expr) {
|
||||||
std::cout << "primop\n";
|
|
||||||
|
|
||||||
Value cur = TRY(expr.rest());
|
Value cur = TRY(expr.rest());
|
||||||
Array code = TRY(Array::create());
|
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<Nil>()) {
|
while (!cur.is<Nil>()) {
|
||||||
Pair& pair = *cur.to<Pair>();
|
Pair& pair = *cur.to<Pair>();
|
||||||
auto subexpr = TRY(pair.first());
|
auto subexpr = TRY(pair.first());
|
||||||
|
|
||||||
auto comp = TRY(compile_expr(context, subexpr));
|
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());
|
cur = TRY(pair.rest());
|
||||||
}
|
}
|
||||||
return ERROR(TypeMismatch);
|
|
||||||
|
Expression ex = Expression(reg, TRY(Array::create()));
|
||||||
|
return ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_list(Context& context, Pair& expr) {
|
Result<Expression> Compiler::compile_list(Context& context, Pair& expr) {
|
||||||
auto first = TRY(expr.first());
|
auto first = TRY(expr.first());
|
||||||
|
|
||||||
|
@ -80,3 +104,11 @@ Result<Expression> Compiler::compile_list(Context& context, Pair& expr) {
|
||||||
}
|
}
|
||||||
return ERROR(TypeMismatch);
|
return ERROR(TypeMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Expression> 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;
|
||||||
|
}
|
||||||
|
|
|
@ -19,4 +19,5 @@ class Compiler {
|
||||||
Result<Expression> compile_expr(Context& context, Value& expr);
|
Result<Expression> compile_expr(Context& context, Value& expr);
|
||||||
Result<Expression> compile_list(Context& context, Pair& expr);
|
Result<Expression> compile_list(Context& context, Pair& expr);
|
||||||
Result<Expression> compile_primop(Context& context, Symbol& op, Pair& expr);
|
Result<Expression> compile_primop(Context& context, Symbol& op, Pair& expr);
|
||||||
|
Result<Expression> compile_int64(Context& context, Int64& value);
|
||||||
};
|
};
|
||||||
|
|
59
src/opcode.hpp
Normal file
59
src/opcode.hpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
13
src/pod.hpp
13
src/pod.hpp
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "opcode.hpp"
|
||||||
#include "result.hpp"
|
#include "result.hpp"
|
||||||
#include "sourcerange.hpp"
|
#include "sourcerange.hpp"
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ enum class Tag : uint8_t {
|
||||||
Array,
|
Array,
|
||||||
ByteArray,
|
ByteArray,
|
||||||
Dict,
|
Dict,
|
||||||
|
Opcode,
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -142,6 +144,17 @@ class PodPair : public PodObject {
|
||||||
OffPtr<PodObject> rest;
|
OffPtr<PodObject> rest;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PodOpcode final : public PodObject {
|
||||||
|
public:
|
||||||
|
PodOpcode() : PodObject(Tag::Opcode){};
|
||||||
|
|
||||||
|
Oc opcode;
|
||||||
|
OpArg arg1;
|
||||||
|
OpArg arg2;
|
||||||
|
OpArg arg3;
|
||||||
|
OpArg arg4;
|
||||||
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class Ptr {
|
class Ptr {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
StaticArena<64 * 1024 * 1024> arena;
|
StaticArena<64 * 1024 * 1024> arena;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
auto s = DIEX(String::create("(+ 1 2 3)"));
|
auto s = DIEX(String::create("(+ (+ 1 2 3) 4)"));
|
||||||
auto reader = Reader(s);
|
auto reader = Reader(s);
|
||||||
|
|
||||||
auto r = DIEX(reader.read_one());
|
auto r = DIEX(reader.read_one());
|
||||||
|
|
|
@ -24,6 +24,8 @@ Result<String> Writer::write_one(Value& obj) {
|
||||||
return write_syntax(*obj.to<Syntax>());
|
return write_syntax(*obj.to<Syntax>());
|
||||||
case Tag::Pair:
|
case Tag::Pair:
|
||||||
return write_pair(*obj.to<Pair>());
|
return write_pair(*obj.to<Pair>());
|
||||||
|
case Tag::Opcode:
|
||||||
|
return write_opcode(*obj.to<Opcode>());
|
||||||
};
|
};
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
@ -212,6 +214,10 @@ Result<String> Writer::write_dict(Dict& val) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_opcode(Opcode& val) {
|
||||||
|
return ERROR(NotImplemented);
|
||||||
|
}
|
||||||
|
|
||||||
Result<String> write_one(Value& value) {
|
Result<String> write_one(Value& value) {
|
||||||
auto w = Writer();
|
auto w = Writer();
|
||||||
return w.write_one(value);
|
return w.write_one(value);
|
||||||
|
|
|
@ -22,6 +22,7 @@ class Writer {
|
||||||
Result<String> write_dict(Dict& val);
|
Result<String> write_dict(Dict& val);
|
||||||
Result<String> write_symbol(Symbol& val);
|
Result<String> write_symbol(Symbol& val);
|
||||||
Result<String> write_syntax(Syntax& val);
|
Result<String> write_syntax(Syntax& val);
|
||||||
|
Result<String> write_opcode(Opcode& val);
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<String> write_one(Value& value);
|
Result<String> write_one(Value& value);
|
||||||
|
|
Loading…
Reference in a new issue