From 2fc4f728643f78577c26e548619bc7db90a7c6ae Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Fri, 28 Jun 2024 18:32:56 +0300
Subject: implement enough for fibonacci

---
 src/common.h          |  5 +++++
 src/compile/compile.c | 34 ++++++++++++++++++++++++++++++++++
 src/ejit.c            | 17 +++++++++++++++++
 src/interp.c          | 32 ++++++++++++++++++++++++--------
 src/vec.h             | 17 +++++++++++++----
 5 files changed, 93 insertions(+), 12 deletions(-)

(limited to 'src')

diff --git a/src/common.h b/src/common.h
index 8f42985..1f52f76 100644
--- a/src/common.h
+++ b/src/common.h
@@ -55,8 +55,12 @@ enum ejit_opcode {
 
 	ADDR,
 	ADDR_F,
+	ADDI,
+
 	SUBR,
 	SUBR_F,
+	SUBI,
+
 	MULR,
 	DIVR,
 	NEGR,
@@ -67,6 +71,7 @@ enum ejit_opcode {
 	BLTR,
 	BNEI,
 	BEQI,
+	BGTI,
 	JMP,
 
 	PARAM,
diff --git a/src/compile/compile.c b/src/compile/compile.c
index ef3efcd..c07a46a 100644
--- a/src/compile/compile.c
+++ b/src/compile/compile.c
@@ -108,6 +108,14 @@ static void compile_addr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	putloc(f, j, i.r0, dst);
 }
 
+static void compile_addi(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+{
+	jit_gpr_t dst = getreg(f, i.r0, 0);
+	jit_gpr_t src0 = getloc(f, j, i.r1, 1);
+	jit_addi(j, dst, src0, i.o);
+	putloc(f, j, i.r0, dst);
+}
+
 static void compile_subr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
 {
 	jit_gpr_t dst = getreg(f, i.r0, 0);
@@ -117,6 +125,14 @@ static void compile_subr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	putloc(f, j, i.r0, dst);
 }
 
+static void compile_subi(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+{
+	jit_gpr_t dst = getreg(f, i.r0, 0);
+	jit_gpr_t src0 = getloc(f, j, i.r1, 1);
+	jit_subi(j, dst, src0, i.o);
+	putloc(f, j, i.r0, dst);
+}
+
 static void compile_stxi64(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
 {
 	jit_gpr_t r0 = getloc(f, j, i.r0, 0);
@@ -194,6 +210,14 @@ static void compile_bnei(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	vect_append(struct reloc_helper, *relocs, &h);
 }
 
+static void compile_bgti(struct ejit_func *f, jit_state_t *j, struct ejit_insn i, struct vec *relocs)
+{
+	jit_gpr_t r1 = getloc(f, j, i.r1, 0);
+	jit_reloc_t r = jit_bgti(j, r1, i.o);
+	struct reloc_helper h = {.r = r, .to = i.r0};
+	vect_append(struct reloc_helper, *relocs, &h);
+}
+
 static void compile_jmp(struct ejit_func *f, jit_state_t *j, struct ejit_insn i, struct vec *relocs)
 {
 	(void)(f);
@@ -326,7 +350,9 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 		case MOVR: compile_movr(f, j, i); break;
 		case MOVI: compile_movi(f, j, i); break;
 		case ADDR: compile_addr(f, j, i); break;
+		case ADDI: compile_addi(f, j, i); break;
 		case SUBR: compile_subr(f, j, i); break;
+		case SUBI: compile_subi(f, j, i); break;
 
 		case STXI64: compile_stxi64(f, j, i); break;
 		case LDXIU64: compile_ldxiu64(f, j, i); break;
@@ -337,6 +363,7 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 		case BLTR: compile_bltr(f, j, i, &relocs); break;
 		case BEQI: compile_beqi(f, j, i, &relocs); break;
 		case BNEI: compile_bnei(f, j, i, &relocs); break;
+		case BGTI: compile_bgti(f, j, i, &relocs); break;
 		case JMP: compile_jmp(f, j, i, &relocs); break;
 
 		case ARG: {
@@ -395,6 +422,13 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 			break;
 		}
 
+		case RET_I: {
+			jit_shrink_stack(j, stack);
+			jit_leave_jit_abi(j, gprs, fprs, frame);
+			jit_reti(j, i.o);
+			break;
+		}
+
 		case END: {
 			/* 'void' return */
 			jit_shrink_stack(j, stack);
diff --git a/src/ejit.c b/src/ejit.c
index 2040865..1fcae9d 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -199,6 +199,11 @@ void ejit_addr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, st
 	emit_insn_r(s, ADDR_F, r0.f, r1.f, r2.f);
 }
 
+void ejit_addi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, long o)
+{
+	emit_insn_i(s, ADDI, r0.r, r1.r, o);
+}
+
 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);
@@ -209,6 +214,11 @@ void ejit_subr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, st
 	emit_insn_r(s, SUBR_F, r0.f, r1.f, r2.f);
 }
 
+void ejit_subi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, long o)
+{
+	emit_insn_i(s, SUBI, r0.r, r1.r, o);
+}
+
 void ejit_mulr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2)
 {
 	emit_insn_r(s, MULR, r0.r, r1.r, r2.r);
@@ -268,6 +278,13 @@ struct ejit_reloc ejit_beqi(struct ejit_func *s, struct ejit_gpr r0, long o)
 	return (struct ejit_reloc){.insn = addr};
 }
 
+struct ejit_reloc ejit_bgti(struct ejit_func *s, struct ejit_gpr r0, long o)
+{
+	size_t addr = vec_len(&s->insns);
+	emit_insn_i(s, BGTI, 0, r0.r, o);
+	return (struct ejit_reloc){.insn = addr};
+}
+
 struct ejit_reloc ejit_jmp(struct ejit_func *s)
 {
 	size_t addr = vec_len(&s->insns);
diff --git a/src/interp.c b/src/interp.c
index 9c3aea3..25f723a 100644
--- a/src/interp.c
+++ b/src/interp.c
@@ -2,7 +2,6 @@
 
 #include "common.h"
 
-
 union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], bool run, void ***labels_wb)
 {
 	static void *labels[OPCODE_COUNT] = {
@@ -12,8 +11,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 
 		[ADDR] = &&ADDR,
 		[ADDR_F] = &&ADDR_F,
+		[ADDI] = &&ADDI,
+
 		[SUBR] = &&SUBR,
 		[SUBR_F] = &&SUBR_F,
+		[SUBI] = &&SUBI,
 
 		[MULR] = &&MULR,
 		[DIVR] = &&DIVR,
@@ -27,6 +29,8 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 		[BLTR] = &&BLTR,
 		[BNEI] = &&BNEI,
 		[BEQI] = &&BEQI,
+		[BGTI] = &&BGTI,
+
 		[JMP] = &&JMP,
 
 		[RET] = &&RET,
@@ -57,21 +61,19 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 		return (union interp_ret){.r = 0};
 	}
 
-	/** @todo this can be optimized by for example using a common buffer
-	 * 'stack' */
 	long *gpr = malloc(f->gpr * sizeof(long));
-	long *fpr = malloc(f->fpr * sizeof(long));
+	double *fpr = malloc(f->fpr * sizeof(double));
+
 	struct vec call_args = vec_create(sizeof(struct ejit_arg));
 	struct ejit_insn *insns = f->insns.buf;
 
-	struct ejit_insn i;
 	/* retval is kind of an unfortunate extra bit of state to keep track of,
 	 * but having call and return value separated is pretty convenient for
 	 * void calls so I guess I don't mind? */
 	long retval = 0; double retval_f = 0.;
 	size_t pc = 0;
 
-#define DO(x) x: { i = insns[pc];
+#define DO(x) x: { struct ejit_insn i = insns[pc]; (void)i;
 #define JUMP(a) goto *insns[pc = a].addr;
 #define DISPATCH() } goto *insns[++pc].addr;
 
@@ -104,6 +106,10 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 	fpr[i.r0] = fpr[i.r1] + fpr[i.r2];
 	DISPATCH();
 
+	DO(ADDI);
+	gpr[i.r0] = gpr[i.r1] + i.o;
+	DISPATCH();
+
 	DO(SUBR);
 	gpr[i.r0] = gpr[i.r1] - gpr[i.r2];
 	DISPATCH();
@@ -112,6 +118,10 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 	fpr[i.r0] = fpr[i.r1] - fpr[i.r2];
 	DISPATCH();
 
+	DO(SUBI);
+	gpr[i.r0] = gpr[i.r1] - i.o;
+	DISPATCH();
+
 	DO(MULR);
 	gpr[i.r0] = gpr[i.r1] * gpr[i.r2];
 	DISPATCH();
@@ -156,6 +166,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 
 	DISPATCH();
 
+	DO(BGTI);
+	if (gpr[i.r1] > i.o)
+		JUMP(i.r0);
+
+	DISPATCH();
+
 	DO(JMP);
 	JUMP(i.r0);
 	DISPATCH();
@@ -237,14 +253,14 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 #undef DO
 
 out_int:
-	vec_destroy(&call_args);
 	free(gpr);
 	free(fpr);
+	vec_destroy(&call_args);
 	return (union interp_ret){.r = retval};
 
 out_float:
-	vec_destroy(&call_args);
 	free(gpr);
 	free(fpr);
+	vec_destroy(&call_args);
 	return (union interp_ret){.d = retval_f};
 }
diff --git a/src/vec.h b/src/vec.h
index e998e27..7e6b5be 100644
--- a/src/vec.h
+++ b/src/vec.h
@@ -33,11 +33,12 @@ struct vec {
 
 static inline struct vec vec_create(size_t ns)
 {
+	const size_t s = 8;
 	return (struct vec) {
 		       .n = 0,
-		       .s = 1,
+		       .s = s,
 		       .ns = ns,
-		       .buf = malloc(ns),
+		       .buf = malloc(s * ns),
 	};
 }
 
@@ -98,8 +99,16 @@ static inline void vec_reserve(struct vec *v, size_t n)
 		return;
 
 	v->n = n;
-	v->s = n;
-	v->buf = realloc(v->buf, v->s * v->ns);
+	if (v->s < v->n) {
+		v->s *= 2;
+		v->buf = realloc(v->buf, v->s * v->ns);
+	}
+}
+
+static inline void vec_shrink(struct vec *v, size_t n)
+{
+	assert(v->n >= n);
+	v->n = n;
 }
 
 #endif /* VEC_H */
-- 
cgit v1.2.3