aboutsummaryrefslogtreecommitdiff
path: root/src/ejit.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-06-23 23:31:46 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-06-23 23:38:49 +0300
commit5a4da8bac457f0e70e690a572eba9cf754e69a37 (patch)
tree58e48f1b12722eadbc1b2587b690b30afac54140 /src/ejit.c
downloadejit-5a4da8bac457f0e70e690a572eba9cf754e69a37.tar.gz
ejit-5a4da8bac457f0e70e690a572eba9cf754e69a37.zip
initial interpeter testing
Diffstat (limited to 'src/ejit.c')
-rw-r--r--src/ejit.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/ejit.c b/src/ejit.c
new file mode 100644
index 0000000..bd5a652
--- /dev/null
+++ b/src/ejit.c
@@ -0,0 +1,190 @@
+#include <assert.h>
+#include <sys/mman.h>
+
+#include <ejit/ejit.h>
+
+#include "common.h"
+
+static void emit_insn_i(struct ejit_func *f, enum ejit_opcode op, size_t r0, size_t r1, long o)
+{
+ struct ejit_insn i = {.op = op, .r0 = r0, .r1 = r1, .o = o};
+ vec_append(&f->insns, &i);
+}
+
+static void emit_insn_r(struct ejit_func *f, enum ejit_opcode op, size_t r0, size_t r1, size_t r2)
+{
+ struct ejit_insn i = {.op = op, .r0 = r0, .r1 = r1, .r2 = r2};
+ vec_append(&f->insns, &i);
+}
+
+static void emit_insn_p(struct ejit_func *f, enum ejit_opcode op, size_t r0, size_t r1, void *p)
+{
+ struct ejit_insn i = {.op = op, .r0 = r0, .r1 = r1, .p = p};
+ vec_append(&f->insns, &i);
+}
+
+static void emit_insn_f(struct ejit_func *f, enum ejit_opcode op, size_t r0, size_t r1, double d)
+{
+ struct ejit_insn i = {.op = op, .r0 = r0, .r1 = r1, .d = d};
+ vec_append(&f->insns, &i);
+}
+
+struct ejit_func *ejit_create_func(enum ejit_type rtype, size_t argc, const struct ejit_operand args[argc])
+{
+ struct ejit_func *f = malloc(sizeof(struct ejit_func));
+ assert(f);
+
+ f->rtype = rtype;
+
+ f->insns = vec_create(sizeof(struct ejit_insn));
+ f->arena = NULL;
+ f->size = 0;
+
+ emit_insn_i(f, START, 0, 0, 0);
+
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_i(f, PARAM, args[i].r, 0, i); break;
+ case EJIT_OPERAND_FPR: emit_insn_i(f, PARAM_F, args[i].r, 0, i); break;
+ default: abort();
+ }
+ }
+
+ return f;
+}
+
+void ejit_compile_func(struct ejit_func *f, size_t gpr, size_t fpr)
+{
+ f->gpr = gpr;
+ f->fpr = fpr;
+ /** @todo try to implement JIT */
+ /* otherwise, convert opcodes to address labels */
+
+ void **labels;
+ /* just get labels, don't actually run anything yet */
+ ejit_interp(f, 0, NULL, false, &labels);
+ foreach_vec(ii, f->insns) {
+ struct ejit_insn i = vect_at(struct ejit_insn, f->insns, ii);
+ i.addr = labels[i.op];
+ vect_at(struct ejit_insn, f->insns, ii) = i;
+ }
+}
+
+void ejit_destroy_func(struct ejit_func *f)
+{
+ if (f->arena)
+ munmap(f->arena, f->size);
+
+ vec_destroy(&f->insns);
+ free(f);
+}
+
+struct ejit_label ejit_label(struct ejit_func *f)
+{
+ return (struct ejit_label){.addr = vec_len(&f->insns)};
+}
+
+void ejit_patch(struct ejit_func *f, struct ejit_reloc r, struct ejit_label l)
+{
+ struct ejit_insn i = vect_at(struct ejit_insn, f->insns, r.insn);
+ /** @todo some assert that checks the opcode? */
+ i.o = l.addr;
+ vect_at(struct ejit_insn, f->insns, r.insn) = i;
+}
+
+void ejit_calli(struct ejit_func *s, struct ejit_func *f, size_t argc, const struct ejit_operand args[argc])
+{
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_i(s, ARG, args[i].r, args[i].type, 0); break;
+ case EJIT_OPERAND_FPR: emit_insn_i(s, ARG_F, args[i].r, args[i].type, 0); break;
+ case EJIT_OPERAND_IMM: emit_insn_i(s, ARG_I, 0, args[i].type, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, 0, args[i].type, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_p(s, CALLI, 0, 0, f);
+}
+
+void ejit_escapei(struct ejit_func *s, ejit_escape_t f, size_t argc, const struct ejit_operand args[argc])
+{
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_i(s, ARG, args[i].r, 0, 0); break;
+ case EJIT_OPERAND_FPR: emit_insn_i(s, ARG_F, args[i].r, 0, 0); break;
+ case EJIT_OPERAND_IMM: emit_insn_i(s, ARG_I, 0, 0, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, 0, 0, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_p(s, ESCAPEI, 0, 0, f);
+}
+
+void ejit_escapei_f(struct ejit_func *s, ejit_escape_f_t f, size_t argc, const struct ejit_operand args[argc])
+{
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_i(s, ARG, args[i].r, 0, 0); break;
+ case EJIT_OPERAND_FPR: emit_insn_i(s, ARG_F, args[i].r, 0, 0); break;
+ case EJIT_OPERAND_IMM: emit_insn_i(s, ARG_I, 0, 0, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, 0, 0, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_p(s, ESCAPEI_F, 0, 0, f);
+}
+
+void ejit_ret(struct ejit_func *s, struct ejit_gpr r0)
+{
+ emit_insn_r(s, RET, r0.r, 0, 0);
+}
+
+void ejit_ret_f(struct ejit_func *s, struct ejit_fpr r0)
+{
+ emit_insn_r(s, RET_F, r0.f, 0, 0);
+}
+
+void ejit_ret_i(struct ejit_func *s, long i)
+{
+ emit_insn_i(s, RET_I, 0, 0, i);
+}
+
+void ejit_ret_fi(struct ejit_func *s, double f)
+{
+ emit_insn_f(s, RET_FI, 0, 0, f);
+}
+
+void ejit_addr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2)
+{
+ emit_insn_r(s, ADDR, r0.r, r1.r, r2.r);
+}
+
+void ejit_addr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2)
+{
+ emit_insn_r(s, ADDR_F, r0.f, r1.f, r2.f);
+}
+
+void ejit_subr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2)
+{
+ emit_insn_r(s, SUBR, r0.r, r1.r, r2.r);
+}
+
+void ejit_subr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2)
+{
+ emit_insn_r(s, SUBR_F, r0.f, r1.f, r2.f);
+}
+
+void ejit_movi(struct ejit_func *s, struct ejit_gpr r0, long o)
+{
+ emit_insn_i(s, MOVI, r0.r, 0, o);
+}
+
+struct ejit_reloc ejit_bltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
+{
+ struct ejit_label label = ejit_label(s);
+ emit_insn_i(s, BLTR, r0.r, r1.r, 0);
+ return (struct ejit_reloc){.insn = label.addr};
+}