From 49aa680ccdac46d1d2a7f9f250999b7ff7099548 Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Sat, 29 Jun 2024 14:20:07 +0300
Subject: start adding tests

---
 src/common.h          |  20 +++++---
 src/compile/compile.c | 127 ++++++++++++++++++++++++++++------------------
 src/ejit.c            | 137 +++++++++++++++++++++++++++++++++-----------------
 src/interp.c          |  40 +++++++++------
 4 files changed, 207 insertions(+), 117 deletions(-)

(limited to 'src')

diff --git a/src/common.h b/src/common.h
index 1f2289d..c3442c6 100644
--- a/src/common.h
+++ b/src/common.h
@@ -57,6 +57,8 @@ enum ejit_opcode {
 	ADDR_F,
 	ADDI,
 
+	ABSR_F,
+
 	SUBR,
 	SUBR_F,
 	SUBI,
@@ -88,10 +90,10 @@ enum ejit_opcode {
 	CALLI,
 	CALLI_F,
 
-	RET,
-	RET_I,
-	RET_F,
-	RET_FI,
+	RETR,
+	RETI,
+	RETR_F,
+	RETI_F,
 
 	RETVAL,
 	RETVAL_F,
@@ -132,7 +134,7 @@ struct ejit_func {
 
 
 union interp_ret {
-	long r;
+	int64_t r;
 	double d;
 };
 
@@ -142,9 +144,13 @@ struct interp_state {
 	struct vec args;
 };
 
-union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *state, bool run, void ***labels_wb);
+union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
+                             struct ejit_arg args[argc],
+                             struct interp_state *state, bool run,
+                             void ***labels_wb);
 
-long ejit_run_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *state);
+int64_t ejit_run_interp(struct ejit_func *f, size_t argc,
+                     struct ejit_arg args[argc], struct interp_state *state);
 
 bool ejit_compile(struct ejit_func *f);
 
diff --git a/src/compile/compile.c b/src/compile/compile.c
index c07a46a..c9a92a2 100644
--- a/src/compile/compile.c
+++ b/src/compile/compile.c
@@ -5,8 +5,8 @@
 static void *alloc_arena(size_t size)
 {
 	return mmap(NULL, size,
-			PROT_EXEC | PROT_READ | PROT_WRITE,
-			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	            PROT_EXEC | PROT_READ | PROT_WRITE,
+	            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 }
 
 static void free_arena(void *arena, size_t size)
@@ -27,7 +27,7 @@ static size_t frploc_count(struct ejit_func *f)
 static size_t stack_size(struct ejit_func *f)
 {
 	return grploc_count(f) * sizeof(jit_uword_t)
-		+ frploc_count(f) * sizeof(jit_float64_t);
+	       + frploc_count(f) * sizeof(jit_float64_t);
 }
 
 static jit_off_t stack_loc(size_t l)
@@ -40,7 +40,7 @@ static jit_off_t stack_loc_f(struct ejit_func *f, size_t l)
 {
 	assert(l >= jit_vf_num());
 	return grploc_count(f) * sizeof(jit_uword_t)
-		+ (l - jit_vf_num()) * sizeof(jit_float64_t);
+	       + (l - jit_vf_num()) * sizeof(jit_float64_t);
 }
 
 
@@ -84,14 +84,16 @@ static void compile_label(jit_state_t *j, size_t ii, struct vec *labels)
 	vect_at(jit_addr_t, *labels, ii) = jit_address(j);
 }
 
-static void compile_movi(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+static void compile_movi(struct ejit_func *f, jit_state_t *j,
+                         struct ejit_insn i)
 {
 	jit_gpr_t r = getreg(f, i.r0, 0);
 	jit_movi(j, r, i.o);
 	putloc(f, j, i.r0, r);
 }
 
-static void compile_movr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+static void compile_movr(struct ejit_func *f, jit_state_t *j,
+                         struct ejit_insn i)
 {
 	jit_gpr_t to = getreg(f, i.r0, 0);
 	jit_gpr_t from = getreg(f, i.r1, 1);
@@ -99,7 +101,8 @@ static void compile_movr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	putloc(f, j, i.r0, to);
 }
 
-static void compile_addr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+static void compile_addr(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);
@@ -108,7 +111,8 @@ 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)
+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);
@@ -116,7 +120,8 @@ static void compile_addi(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	putloc(f, j, i.r0, dst);
 }
 
-static void compile_subr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+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);
 	jit_gpr_t src0 = getloc(f, j, i.r1, 1);
@@ -125,7 +130,8 @@ 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)
+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);
@@ -133,14 +139,16 @@ static void compile_subi(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	putloc(f, j, i.r0, dst);
 }
 
-static void compile_stxi64(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+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);
 	jit_gpr_t r1 = getloc(f, j, i.r1, 1);
 	jit_stxi_l(j, i.o, r1, r0);
 }
 
-static void compile_ldxiu64(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+static void compile_ldxiu64(struct ejit_func *f, jit_state_t *j,
+                            struct ejit_insn i)
 {
 	jit_gpr_t r0 = getreg(f, i.r0, 0);
 	jit_gpr_t r1 = getloc(f, j, i.r1, 1);
@@ -148,8 +156,10 @@ static void compile_ldxiu64(struct ejit_func *f, jit_state_t *j, struct ejit_ins
 	putloc(f, j, i.r0, r0);
 }
 
-static void compile_reg_cmp(struct ejit_func *f, jit_state_t *j, struct ejit_insn i,
-		jit_reloc_t (*bcomp)(jit_state_t *, jit_gpr_t, jit_gpr_t), long same)
+static void compile_reg_cmp(struct ejit_func *f, jit_state_t *j,
+                            struct ejit_insn i,
+                            jit_reloc_t (*bcomp)(jit_state_t *, jit_gpr_t,
+                                                 jit_gpr_t), long same)
 {
 	jit_gpr_t r0 = getreg(f, i.r0, 0);
 	if (i.r1 == i.r2) {
@@ -185,7 +195,8 @@ static void compile_ltr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
 	compile_reg_cmp(f, j, i, jit_bltr, 0);
 }
 
-static void compile_bltr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i, struct vec *relocs)
+static void compile_bltr(struct ejit_func *f, jit_state_t *j,
+                         struct ejit_insn i, struct vec *relocs)
 {
 	jit_gpr_t c0 = getloc(f, j, i.r1, 0);
 	jit_gpr_t c1 = getloc(f, j, i.r2, 1);
@@ -194,7 +205,8 @@ static void compile_bltr(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	vect_append(struct reloc_helper, *relocs, &h);
 }
 
-static void compile_beqi(struct ejit_func *f, jit_state_t *j, struct ejit_insn i, struct vec *relocs)
+static void compile_beqi(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_beqi(j, r1, i.o);
@@ -202,7 +214,8 @@ static void compile_beqi(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	vect_append(struct reloc_helper, *relocs, &h);
 }
 
-static void compile_bnei(struct ejit_func *f, jit_state_t *j, struct ejit_insn i, struct vec *relocs)
+static void compile_bnei(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_bnei(j, r1, i.o);
@@ -210,7 +223,8 @@ 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)
+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);
@@ -218,7 +232,8 @@ static void compile_bgti(struct ejit_func *f, jit_state_t *j, struct ejit_insn i
 	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)
+static void compile_jmp(struct ejit_func *f, jit_state_t *j, struct ejit_insn i,
+                        struct vec *relocs)
 {
 	(void)(f);
 	jit_reloc_t r = jit_jmp(j);
@@ -226,7 +241,8 @@ static void compile_jmp(struct ejit_func *f, jit_state_t *j, struct ejit_insn i,
 	vect_append(struct reloc_helper, *relocs, &h);
 }
 
-static void compile_retval(struct ejit_func *f, jit_state_t *j, struct ejit_insn i)
+static void compile_retval(struct ejit_func *f, jit_state_t *j,
+                           struct ejit_insn i)
 {
 	jit_gpr_t r0 = getreg(f, i.r0, 0);
 	jit_retval(j, r0);
@@ -256,14 +272,14 @@ static enum jit_operand_abi jit_abi_from(enum ejit_type t)
 static size_t arg_offsetof(enum ejit_type t)
 {
 	switch (t) {
-	case EJIT_INT8: return offsetof(struct ejit_arg, c);
-	case EJIT_INT16: return offsetof(struct ejit_arg, s);
-	case EJIT_INT32: return offsetof(struct ejit_arg, i);
-	case EJIT_INT64: return offsetof(struct ejit_arg, l);
-	case EJIT_UINT8: return offsetof(struct ejit_arg, uc);
-	case EJIT_UINT16: return offsetof(struct ejit_arg, us);
-	case EJIT_UINT32: return offsetof(struct ejit_arg, ui);
-	case EJIT_UINT64: return offsetof(struct ejit_arg, ul);
+	case EJIT_INT8: return offsetof(struct ejit_arg, i8);
+	case EJIT_INT16: return offsetof(struct ejit_arg, i16);
+	case EJIT_INT32: return offsetof(struct ejit_arg, i32);
+	case EJIT_INT64: return offsetof(struct ejit_arg, i64);
+	case EJIT_UINT8: return offsetof(struct ejit_arg, u8);
+	case EJIT_UINT16: return offsetof(struct ejit_arg, u16);
+	case EJIT_UINT32: return offsetof(struct ejit_arg, u32);
+	case EJIT_UINT64: return offsetof(struct ejit_arg, u64);
 	case EJIT_POINTER: return offsetof(struct ejit_arg, p);
 	case EJIT_FLOAT: return offsetof(struct ejit_arg, f);
 	case EJIT_DOUBLE: return offsetof(struct ejit_arg, d);
@@ -282,7 +298,8 @@ static jit_off_t arg_offset(struct ejit_insn i)
 
 static jit_off_t type_offset(struct ejit_insn i)
 {
-	return (sizeof(struct ejit_arg) * i.r0) + offsetof(struct ejit_arg, type);
+	return (sizeof(struct ejit_arg) * i.r0) + offsetof(struct ejit_arg,
+	                                                   type);
 }
 
 static void fixup_operands(struct vec *operands, size_t fixup)
@@ -297,7 +314,8 @@ static void fixup_operands(struct vec *operands, size_t fixup)
 	}
 }
 
-static void compile_imm_call(jit_state_t *j, struct vec *src, struct vec *dst, void *addr, size_t argc, jit_operand_t args[argc])
+static void compile_imm_call(jit_state_t *j, struct vec *src, struct vec *dst,
+                             void *addr, size_t argc, jit_operand_t args[argc])
 {
 	/* each move is type + arg, so twofold */
 	size_t movec = vec_len(src) / 2;
@@ -313,7 +331,8 @@ static void compile_imm_call(jit_state_t *j, struct vec *src, struct vec *dst, v
 	vec_reset(dst);
 }
 
-static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, size_t size)
+static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
+                              size_t size)
 {
 	jit_begin(j, arena, size);
 	size_t gprs = f->gpr >= jit_v_num() ? jit_v_num() : f->gpr;
@@ -323,8 +342,8 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 	/* very important, argc we don't really do anything with but JIR_R1
 	 * contains the argument stack! */
 	jit_load_args_2(j,
-			jit_operand_gpr(JIT_OPERAND_ABI_WORD, JIT_R0),
-			jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R1));
+	                jit_operand_gpr(JIT_OPERAND_ABI_WORD, JIT_R0),
+	                jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R1));
 
 	size_t stack = jit_align_stack(j, stack_size(f));
 
@@ -367,24 +386,29 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 		case JMP: compile_jmp(f, j, i, &relocs); break;
 
 		case ARG: {
-			jit_operand_t type = jit_operand_imm(JIT_OPERAND_ABI_WORD, i.r1);
+			jit_operand_t type =
+				jit_operand_imm(JIT_OPERAND_ABI_WORD, i.r1);
 			jit_operand_t arg;
 			if (i.r0 < jit_v_num()) {
 				/* regular register */
-				arg = jit_operand_gpr(jit_abi_from(i.r1), jit_v(i.r2));
+				arg = jit_operand_gpr(jit_abi_from(i.r1),
+				                      jit_v(i.r2));
 			}
 			else {
 				/* stack location, note that we'll fix up the SP
 				 * offset before doing the actual call */
-				arg = jit_operand_mem(jit_abi_from(i.r1), JIT_SP, stack_loc(i.r0));
+				arg = jit_operand_mem(jit_abi_from(i.r1),
+				                      JIT_SP, stack_loc(i.r0));
 			}
 
 			vec_append(&src, &type);
 			vec_append(&src, &arg);
 
 			jit_operand_t to[2] = {
-				jit_operand_mem(JIT_OPERAND_ABI_WORD, JIT_SP, type_offset(i)),
-				jit_operand_mem(jit_abi_from(i.r1), JIT_SP, arg_offset(i))
+				jit_operand_mem(JIT_OPERAND_ABI_WORD, JIT_SP,
+				                type_offset(i)),
+				jit_operand_mem(jit_abi_from(i.r1), JIT_SP,
+				                arg_offset(i))
 			};
 
 			vec_append(&dst, &to[0]);
@@ -394,7 +418,8 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 
 		case ESCAPEI: {
 			jit_operand_t args[2] = {
-				jit_operand_imm(JIT_OPERAND_ABI_WORD, vec_len(&src) / 2),
+				jit_operand_imm(JIT_OPERAND_ABI_WORD,
+				                vec_len(&src) / 2),
 				jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_SP)
 			};
 			compile_imm_call(j, &src, &dst, (void *)i.o, 2, args);
@@ -404,7 +429,8 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 		case CALLI: {
 			jit_operand_t args[3] = {
 				jit_operand_imm(JIT_OPERAND_ABI_POINTER, i.o),
-				jit_operand_imm(JIT_OPERAND_ABI_WORD, vec_len(&src) / 2),
+				jit_operand_imm(JIT_OPERAND_ABI_WORD,
+				                vec_len(&src) / 2),
 				jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_SP)
 			};
 			compile_imm_call(j, &src, &dst, ejit_run_func, 3, args);
@@ -412,7 +438,7 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 		}
 
 		case RETVAL: compile_retval(f, j, i); break;
-		case RET: {
+		case RETR: {
 			jit_gpr_t r = getloc(f, j, i.r0, 0);
 			/* R0 won't get overwritten by jit_leave_jit_abi */
 			jit_movr(j, JIT_R0, r);
@@ -422,7 +448,7 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 			break;
 		}
 
-		case RET_I: {
+		case RETI: {
 			jit_shrink_stack(j, stack);
 			jit_leave_jit_abi(j, gprs, fprs, frame);
 			jit_reti(j, i.o);
@@ -440,19 +466,21 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 		case PARAM: {
 			/* move from argument stack to location */
 			jit_operand_t from = jit_operand_mem(
-					jit_abi_from(i.r1),
-					JIT_R1,
-					arg_offset(i)
-					);
+				jit_abi_from(i.r1),
+				JIT_R1,
+				arg_offset(i)
+				);
 
 			jit_operand_t to;
 			if (i.r0 < jit_v_num()) {
 				/* regular register */
-				to = jit_operand_gpr(jit_abi_from(i.r1), jit_v(i.r2));
+				to = jit_operand_gpr(jit_abi_from(i.r1),
+				                     jit_v(i.r2));
 			}
 			else {
 				/* stack location */
-				to = jit_operand_mem(jit_abi_from(i.r1), JIT_SP, stack_loc(i.r2));
+				to = jit_operand_mem(jit_abi_from(i.r1), JIT_SP,
+				                     stack_loc(i.r2));
 			}
 
 			vec_append(&src, &from);
@@ -474,7 +502,8 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena,
 	}
 
 	foreach_vec(ri, relocs) {
-		struct reloc_helper h = vect_at(struct reloc_helper, relocs, ri);
+		struct reloc_helper h = vect_at(struct reloc_helper, relocs,
+		                                ri);
 		jit_addr_t a = vect_at(jit_addr_t, labels, h.to);
 		jit_reloc_t r = h.r;
 
diff --git a/src/ejit.c b/src/ejit.c
index b059c88..f6f4d8e 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -5,31 +5,36 @@
 
 #include "common.h"
 
-static void emit_insn_i(struct ejit_func *f, enum ejit_opcode op, size_t r0, size_t r1, long o)
+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)
+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)
+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)
+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 *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);
@@ -43,8 +48,10 @@ struct ejit_func *ejit_create_func(enum ejit_type rtype, size_t argc, const stru
 
 	for (size_t i = 0; i < argc; ++i) {
 		switch (args[i].kind) {
-		case EJIT_OPERAND_GPR: emit_insn_r(f, PARAM, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FPR: emit_insn_r(f, PARAM_F, i, args[i].type, args[i].r); break;
+		case EJIT_OPERAND_GPR: emit_insn_r(f, PARAM, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_FPR: emit_insn_r(f, PARAM_F, i, args[i].type,
+			                           args[i].r); break;
 		default: abort();
 		}
 	}
@@ -58,7 +65,8 @@ void ejit_compile_func(struct ejit_func *f, size_t gpr, size_t fpr)
 	ejit_select_compile_func(f, gpr, fpr, true);
 }
 
-void ejit_select_compile_func(struct ejit_func *f, size_t gpr, size_t fpr, bool try_jit)
+void ejit_select_compile_func(struct ejit_func *f, size_t gpr, size_t fpr,
+                              bool try_jit)
 {
 	/* emit a final end instruction in case user didn't do a return */
 	emit_insn_i(f, END, 0, 0, 0);
@@ -109,14 +117,19 @@ void ejit_patch(struct ejit_func *f, struct ejit_reloc r, struct ejit_label l)
 	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])
+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_r(s, ARG, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FPR: emit_insn_r(s, ARG_F, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_IMM: emit_insn_i(s, ARG_I, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, i, args[i].type, args[i].d); break;
+		case EJIT_OPERAND_GPR: emit_insn_r(s, ARG, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_FPR: emit_insn_r(s, ARG_F, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_IMM: emit_insn_i(s, ARG_I, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, i, args[i].type,
+			                           args[i].d); break;
 		default: abort();
 		}
 	}
@@ -124,14 +137,19 @@ void ejit_calli(struct ejit_func *s, struct ejit_func *f, size_t argc, const str
 	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])
+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_r(s, ARG, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FPR: emit_insn_r(s, ARG_F, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_IMM: emit_insn_r(s, ARG_I, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, i, args[i].type, args[i].d); break;
+		case EJIT_OPERAND_GPR: emit_insn_r(s, ARG, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_FPR: emit_insn_r(s, ARG_F, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_IMM: emit_insn_r(s, ARG_I, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, i, args[i].type,
+			                           args[i].d); break;
 		default: abort();
 		}
 	}
@@ -139,14 +157,19 @@ void ejit_escapei(struct ejit_func *s, ejit_escape_t f, size_t argc, const struc
 	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])
+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_r(s, ARG, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FPR: emit_insn_r(s, ARG_F, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_IMM: emit_insn_r(s, ARG_I, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, i, args[i].type, args[i].d); break;
+		case EJIT_OPERAND_GPR: emit_insn_r(s, ARG, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_FPR: emit_insn_r(s, ARG_F, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_IMM: emit_insn_r(s, ARG_I, i, args[i].type,
+			                           args[i].r); break;
+		case EJIT_OPERAND_FLT: emit_insn_f(s, ARG_FI, i, args[i].type,
+			                           args[i].d); break;
 		default: abort();
 		}
 	}
@@ -159,72 +182,87 @@ void ejit_retval(struct ejit_func *s, struct ejit_gpr r0)
 	emit_insn_i(s, RETVAL, r0.r, 0, 0);
 }
 
-void ejit_stxi_64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, long o)
+void ejit_stxi_64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
+                  long o)
 {
 	emit_insn_i(s, STXI64, r0.r, r1.r, o);
 }
 
-void ejit_ldxi_u64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, long o)
+void ejit_ldxi_u64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
+                   long o)
 {
 	emit_insn_i(s, LDXIU64, r0.r, r1.r, o);
 }
 
-void ejit_ret(struct ejit_func *s, struct ejit_gpr r0)
+void ejit_retr(struct ejit_func *s, struct ejit_gpr r0)
 {
-	emit_insn_r(s, RET, r0.r, 0, 0);
+	emit_insn_r(s, RETR, r0.r, 0, 0);
 }
 
-void ejit_ret_f(struct ejit_func *s, struct ejit_fpr r0)
+void ejit_retr_f(struct ejit_func *s, struct ejit_fpr r0)
 {
-	emit_insn_r(s, RET_F, r0.f, 0, 0);
+	emit_insn_r(s, RETR_F, r0.f, 0, 0);
 }
 
-void ejit_ret_i(struct ejit_func *s, long i)
+void ejit_reti(struct ejit_func *s, long i)
 {
-	emit_insn_i(s, RET_I, 0, 0, i);
+	emit_insn_i(s, RETI, 0, 0, i);
 }
 
-void ejit_ret_fi(struct ejit_func *s, double f)
+void ejit_reti_f(struct ejit_func *s, double f)
 {
-	emit_insn_f(s, RET_FI, 0, 0, f);
+	emit_insn_f(s, RETI_F, 0, 0, f);
 }
 
-void ejit_addr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2)
+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)
+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_addi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, long o)
+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)
+void ejit_absr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1)
+{
+	emit_insn_i(s, ABSR_F, r0.f, r1.f, 0);
+}
+
+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)
+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_subi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, long o)
+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)
+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);
 }
 
-void ejit_divr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2)
+void ejit_divr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
+               struct ejit_gpr r2)
 {
 	emit_insn_r(s, DIVR, r0.r, r1.r, r2.r);
 }
@@ -247,17 +285,20 @@ void ejit_movr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
 	emit_insn_i(s, MOVR, r0.r, r1.r, 0);
 }
 
-void ejit_eqr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2)
+void ejit_eqr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
+              struct ejit_gpr r2)
 {
 	emit_insn_r(s, EQR, r0.r, r1.r, r2.r);
 }
 
-void ejit_ltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2)
+void ejit_ltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
+              struct ejit_gpr r2)
 {
 	emit_insn_r(s, LTR, r0.r, r1.r, r2.r);
 }
 
-struct ejit_reloc ejit_bltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
+struct ejit_reloc ejit_bltr(struct ejit_func *s, struct ejit_gpr r0,
+                            struct ejit_gpr r1)
 {
 	size_t addr = vec_len(&s->insns);
 	emit_insn_r(s, BLTR, 0, r0.r, r1.r);
@@ -296,7 +337,7 @@ static struct interp_state create_interp_state()
 {
 	struct interp_state state;
 	state.gprs = vec_create(sizeof(long));
-	state.gprs = vec_create(sizeof(double));
+	state.fprs = vec_create(sizeof(double));
 	state.args = vec_create(sizeof(struct ejit_arg));
 	return state;
 }
@@ -308,7 +349,8 @@ static void destroy_interp_state(struct interp_state state)
 	vec_destroy(&state.args);
 }
 
-long ejit_run_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *state)
+long ejit_run_interp(struct ejit_func *f, size_t argc,
+                     struct ejit_arg args[argc], struct interp_state *state)
 {
 	assert(f->gpr && "trying to run a function that hasn't been compiled");
 	assert(f->rtype == EJIT_VOID || ejit_int_type(f->rtype));
@@ -331,7 +373,8 @@ long ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
 	return r;
 }
 
-double ejit_run_func_f(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
+double ejit_run_func_f(struct ejit_func *f, size_t argc,
+                       struct ejit_arg args[argc])
 {
 	assert(f->fpr && "trying to run a function that hasn't been compiled");
 	assert(ejit_float_type(f->rtype));
diff --git a/src/interp.c b/src/interp.c
index ed7e59c..3395537 100644
--- a/src/interp.c
+++ b/src/interp.c
@@ -1,8 +1,12 @@
 #include <ejit/ejit.h>
+#include <math.h>
 
 #include "common.h"
 
-union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *state, bool run, void ***labels_wb)
+union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
+                             struct ejit_arg args[argc],
+                             struct interp_state *state, bool run,
+                             void ***labels_wb)
 {
 	static void *labels[OPCODE_COUNT] = {
 		[MOVI] = &&MOVI,
@@ -13,6 +17,8 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 		[ADDR_F] = &&ADDR_F,
 		[ADDI] = &&ADDI,
 
+		[ABSR_F] = &&ABSR_F,
+
 		[SUBR] = &&SUBR,
 		[SUBR_F] = &&SUBR_F,
 		[SUBI] = &&SUBI,
@@ -33,10 +39,10 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 
 		[JMP] = &&JMP,
 
-		[RET] = &&RET,
-		[RET_I] = &&RET_I,
-		[RET_F] = &&RET_F,
-		[RET_FI] = &&RET_FI,
+		[RETR] = &&RETR,
+		[RETI] = &&RETI,
+		[RETR_F] = &&RETR_F,
+		[RETI_F] = &&RETI_F,
 
 		[RETVAL] = &&RETVAL,
 
@@ -76,10 +82,10 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 	/* 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.;
+	int64_t retval = 0; double retval_f = 0.;
 	size_t pc = 0;
 
-#define DO(x) x: { struct ejit_insn i = insns[pc]; (void)i;
+#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;
 
@@ -116,6 +122,10 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 	gpr[i.r0] = gpr[i.r1] + i.o;
 	DISPATCH();
 
+	DO(ABSR_F);
+	fpr[i.r0] = fabs(fpr[i.r1]);
+	DISPATCH();
+
 	DO(SUBR);
 	gpr[i.r0] = gpr[i.r1] - gpr[i.r2];
 	DISPATCH();
@@ -187,7 +197,7 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 	DISPATCH();
 
 	DO(PARAM);
-	gpr[i.r2] = args[i.r0].l;
+	gpr[i.r2] = args[i.r0].u64;
 	DISPATCH();
 
 	DO(PARAM_F);
@@ -217,7 +227,8 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 	DO(CALLI);
 	struct ejit_func *f = i.p;
 	size_t argc = vec_len(&state->args) - prev_argc;
-	struct ejit_arg *args = ((struct ejit_arg *)state->args.buf) + prev_argc;
+	struct ejit_arg *args = ((struct ejit_arg *)state->args.buf) +
+	                        prev_argc;
 
 	retval = ejit_run_interp(f, argc, args, state);
 
@@ -232,7 +243,8 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 	DO(ESCAPEI);
 	ejit_escape_t f = i.p;
 	size_t argc = vec_len(&state->args) - prev_argc;
-	struct ejit_arg *args = ((struct ejit_arg *)state->args.buf) + prev_argc;
+	struct ejit_arg *args = ((struct ejit_arg *)state->args.buf) +
+	                        prev_argc;
 
 	retval = f(argc, args);
 
@@ -241,22 +253,22 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a
 
 	/* dispatch is technically unnecessary for returns, but keep it for
 	 * symmetry */
-	DO(RET);
+	DO(RETR);
 	retval = gpr[i.r0];
 	goto out_int;
 	DISPATCH();
 
-	DO(RET_I);
+	DO(RETI);
 	retval = i.o;
 	goto out_int;
 	DISPATCH();
 
-	DO(RET_F);
+	DO(RETR_F);
 	retval_f = fpr[i.r0];
 	goto out_float;
 	DISPATCH();
 
-	DO(RET_FI);
+	DO(RETI_F);
 	retval_f = i.d;
 	goto out_float;
 	DISPATCH();
-- 
cgit v1.2.3