From 67a13eb82534996fbd6ba2fc0c36d3e1284bcd8e Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Wed, 26 Mar 2025 13:17:58 +0200
Subject: handle immediates a bit better

+ Passing floats as immediate values is not supported in lightening, but
  I might have a go at adding it since it seems like a useful feature at
  some point
---
 tests/escapei_immediate_10.c | 73 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 tests/escapei_immediate_10.c

(limited to 'tests/escapei_immediate_10.c')

diff --git a/tests/escapei_immediate_10.c b/tests/escapei_immediate_10.c
new file mode 100644
index 0000000..381c79f
--- /dev/null
+++ b/tests/escapei_immediate_10.c
@@ -0,0 +1,73 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+static int32_t func(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e,
+                    int32_t f, int32_t g, int32_t h, int32_t i, int32_t j)
+{
+	assert(a == 0);
+	assert(b == 1);
+	assert(c == 2);
+	assert(d == 3);
+	assert(e == 4);
+	assert(f == 5);
+	assert(g == 6);
+	assert(h == 7);
+	assert(i == 8);
+	assert(j == 9);
+	return 42;
+}
+
+static long escape_func(size_t argc, const struct ejit_arg args[argc])
+{
+	assert(argc == 10);
+	assert(args[0].type == EJIT_INT32);
+	assert(args[1].type == EJIT_INT32);
+	assert(args[3].type == EJIT_INT32);
+	assert(args[4].type == EJIT_INT32);
+	assert(args[5].type == EJIT_INT32);
+	assert(args[6].type == EJIT_INT32);
+	assert(args[7].type == EJIT_INT32);
+	assert(args[8].type == EJIT_INT32);
+	assert(args[9].type == EJIT_INT32);
+
+	int32_t a = args[0].i32;
+	int32_t b = args[1].i32;
+	int32_t c = args[2].i32;
+	int32_t d = args[3].i32;
+	int32_t e = args[4].i32;
+	int32_t f = args[5].i32;
+	int32_t g = args[6].i32;
+	int32_t h = args[7].i32;
+	int32_t i = args[8].i32;
+	int32_t j = args[9].i32;
+	return func(a, b, c, d, e, f, g, h, i, j);
+}
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_func *f = ejit_create_func(EJIT_INT32, 0, NULL);
+	struct ejit_operand args[10] = {
+		EJIT_OPERAND_IMM(0, EJIT_INT32),
+		EJIT_OPERAND_IMM(1, EJIT_INT32),
+		EJIT_OPERAND_IMM(2, EJIT_INT32),
+		EJIT_OPERAND_IMM(3, EJIT_INT32),
+		EJIT_OPERAND_IMM(4, EJIT_INT32),
+		EJIT_OPERAND_IMM(5, EJIT_INT32),
+		EJIT_OPERAND_IMM(6, EJIT_INT32),
+		EJIT_OPERAND_IMM(7, EJIT_INT32),
+		EJIT_OPERAND_IMM(8, EJIT_INT32),
+		EJIT_OPERAND_IMM(9, EJIT_INT32),
+	};
+	ejit_escapei_i(f, escape_func, 10, args);
+	ejit_retval(f, EJIT_GPR(0));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 11, 0, false, do_jit, true);
+
+	assert(ejit_run_func_i(f, 0, NULL) == 42);
+
+	ejit_destroy_func(f);
+}
-- 
cgit v1.2.3


From d8f9699debd435da5e1aef22c94c47154be4e2be Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Wed, 2 Apr 2025 21:13:03 +0300
Subject: fix big endian compilation

+ Code used some assumptions about type aliasing that might not hold for
  all systems
---
 include/ejit/ejit.h          | 124 ++++++++++++++++++++++++++++++++-----------
 src/ejit.c                   |   6 ++-
 src/interp.c                 |  13 ++++-
 tests/escapei_10.c           |  30 ++++-------
 tests/escapei_double.c       |   6 +--
 tests/escapei_float.c        |   6 +--
 tests/escapei_immediate_10.c |  30 ++++-------
 7 files changed, 134 insertions(+), 81 deletions(-)

(limited to 'tests/escapei_immediate_10.c')

diff --git a/include/ejit/ejit.h b/include/ejit/ejit.h
index 920fdc5..2afdc61 100644
--- a/include/ejit/ejit.h
+++ b/include/ejit/ejit.h
@@ -72,29 +72,20 @@ static inline enum ejit_type ejit_signed_type(size_t w)
 
 struct ejit_arg {
 	union {
-		int8_t i8;
-		uint8_t u8;
+		int8_t  i8;
 		int16_t i16;
-		uint16_t u16;
 		int32_t i32;
-		uint32_t u32;
 		int64_t i64;
-		uint64_t u64;
 
-		signed char c;
-		unsigned char uc;
-		signed short s;
-		unsigned short us;
-		signed int i;
-		unsigned int ui;
-		signed long l;
-		unsigned long ul;
-		signed long long ll;
-		unsigned long long ull;
+		uint8_t  u8;
+		uint16_t u16;
+		uint32_t u32;
+		uint64_t u64;
 
 		float f;
 		double d;
 		void *p;
+		long l;
 	};
 	enum ejit_type type;
 };
@@ -136,15 +127,15 @@ static inline struct ejit_arg ejit_build_arg(enum ejit_type type, uint64_t x)
 	a.type = type;
 
 	switch (type) {
-	case EJIT_INT8: a.u64 = (int8_t)x; break;
-	case EJIT_INT16: a.u64 = (int16_t)x; break;
-	case EJIT_INT32: a.u64 = (int32_t)x; break;
-	case EJIT_INT64: a.u64 = (int64_t)x; break;
-	case EJIT_UINT8: a.u64 = (uint8_t)x; break;
-	case EJIT_UINT16: a.u64 = (uint16_t)x; break;
-	case EJIT_UINT32: a.u64 = (uint32_t)x; break;
-	case EJIT_UINT64: a.u64 = (uint64_t)x; break;
-	case EJIT_POINTER: a.p = (void *)(uintptr_t)x; break;
+	case EJIT_INT8:    a.i8  = (int8_t)x; break;
+	case EJIT_INT16:   a.i16 = (int16_t)x; break;
+	case EJIT_INT32:   a.i32 = (int32_t)x; break;
+	case EJIT_INT64:   a.i64 = (int64_t)x; break;
+	case EJIT_UINT8:   a.u8  = (uint8_t)x; break;
+	case EJIT_UINT16:  a.u16 = (uint16_t)x; break;
+	case EJIT_UINT32:  a.u32 = (uint32_t)x; break;
+	case EJIT_UINT64:  a.u64 = (uint64_t)x; break;
+	case EJIT_POINTER: a.p   = (void *)(uintptr_t)x; break;
 	default: abort();
 	}
 
@@ -251,17 +242,17 @@ void ejit_destroy_func(struct ejit_func *s);
 /* maybe slight hack, but increase width to interpeter register width */
 static inline struct ejit_arg ejit_i8(int8_t a)
 {
-	return (struct ejit_arg){.i64 = a, .type = EJIT_INT8};
+	return (struct ejit_arg){.i8 = a, .type = EJIT_INT8};
 }
 
 static inline struct ejit_arg ejit_i16(int16_t a)
 {
-	return (struct ejit_arg){.i64 = a, .type = EJIT_INT16};
+	return (struct ejit_arg){.i16 = a, .type = EJIT_INT16};
 }
 
 static inline struct ejit_arg ejit_i32(int32_t a)
 {
-	return (struct ejit_arg){.i64 = a, .type = EJIT_INT32};
+	return (struct ejit_arg){.i32 = a, .type = EJIT_INT32};
 }
 
 static inline struct ejit_arg ejit_i64(int64_t a)
@@ -271,22 +262,22 @@ static inline struct ejit_arg ejit_i64(int64_t a)
 
 static inline struct ejit_arg ejit_u8(uint8_t a)
 {
-	return (struct ejit_arg){.i64 = a, .type = EJIT_UINT8};
+	return (struct ejit_arg){.u8 = a, .type = EJIT_UINT8};
 }
 
 static inline struct ejit_arg ejit_u16(uint16_t a)
 {
-	return (struct ejit_arg){.i64 = a, .type = EJIT_UINT16};
+	return (struct ejit_arg){.u16 = a, .type = EJIT_UINT16};
 }
 
 static inline struct ejit_arg ejit_u32(uint32_t a)
 {
-	return (struct ejit_arg){.i64 = a, .type = EJIT_UINT32};
+	return (struct ejit_arg){.u32 = a, .type = EJIT_UINT32};
 }
 
 static inline struct ejit_arg ejit_u64(uint64_t a)
 {
-	return (struct ejit_arg){.i64 = a, .type = EJIT_UINT64};
+	return (struct ejit_arg){.u64 = a, .type = EJIT_UINT64};
 }
 
 static inline struct ejit_arg ejit_pointer(void *p)
@@ -372,6 +363,77 @@ static inline struct ejit_arg ejit_pointer_arg(void *p, size_t w)
 #define EJIT_AUTO(x) \
 	EJIT_ARG(x, typeof(x))
 
+static inline int64_t ejit_signed_param(size_t argc, const struct ejit_arg args[argc],
+		size_t idx, enum ejit_type type)
+{
+	assert(idx < argc);
+	assert(args[idx].type == type);
+	switch (type) {
+	case EJIT_INT64: return args[idx].i64;
+	case EJIT_INT32: return args[idx].i32;
+	case EJIT_INT16: return args[idx].i16;
+	case EJIT_INT8:  return args[idx].i8;
+	default: abort();
+	}
+
+	return 0;
+}
+
+static inline uint64_t ejit_unsigned_param(size_t argc, const struct ejit_arg args[argc],
+		size_t idx, enum ejit_type type)
+{
+	assert(idx < argc);
+	assert(args[idx].type == type);
+	switch (type) {
+	case EJIT_UINT64: return args[idx].u64;
+	case EJIT_UINT32: return args[idx].u32;
+	case EJIT_UINT16: return args[idx].u16;
+	case EJIT_UINT8:  return args[idx].u8;
+	default: abort();
+	}
+}
+
+static inline float ejit_float_param(size_t argc, const struct ejit_arg args[argc],
+		size_t idx, enum ejit_type type)
+{
+	assert(idx < argc);
+	assert(args[idx].type == type && type == EJIT_FLOAT);
+	return args[idx].f;
+}
+
+static inline double ejit_double_param(size_t argc, const struct ejit_arg args[argc],
+		size_t idx, enum ejit_type type)
+{
+	assert(idx < argc);
+	assert(args[idx].type == type && type == EJIT_DOUBLE);
+	return args[idx].d;
+}
+
+static inline void *ejit_pointer_param(size_t argc, const struct ejit_arg args[argc],
+		size_t idx, enum ejit_type type)
+{
+	assert(idx < argc);
+	assert(args[idx].type == type && type == EJIT_POINTER);
+	return args[idx].p;
+}
+
+#define EJIT_PARAM(argc, args, idx, t)                 \
+	_Generic((t)(0),               \
+		 signed char       : ejit_signed_param,      \
+		 signed short      : ejit_signed_param,    \
+		 signed int        : ejit_signed_param,    \
+		 signed long       : ejit_signed_param,    \
+		 signed long long  : ejit_signed_param, \
+		 unsigned char     : ejit_unsigned_param,      \
+		 unsigned short    : ejit_unsigned_param,    \
+		 unsigned int      : ejit_unsigned_param,    \
+		 unsigned long     : ejit_unsigned_param,    \
+		 unsigned long long: ejit_unsigned_param, \
+		 float             : ejit_float_param,    \
+		 double            : ejit_double_param,  \
+		 default           : ejit_pointer_param \
+		 )(argc, args, idx, EJIT_TYPE(t))
+
 static inline bool ejit_use64(struct ejit_arg a)
 {
 	if (a.type == EJIT_INT64 || a.type == EJIT_UINT64)
diff --git a/src/ejit.c b/src/ejit.c
index 2224198..0ee3986 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -1726,6 +1726,10 @@ struct ejit_arg ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg
 		};
 
 	case EJIT_UINT64:
+		return (struct ejit_arg){
+			.u64 = ejit_run_func_l(f, argc, args),
+			.type = f->rtype
+		};
 	case EJIT_INT64:
 		return (struct ejit_arg){
 			.i64 = ejit_run_func_l(f, argc, args),
@@ -1734,7 +1738,7 @@ struct ejit_arg ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg
 
 	default:
 		return (struct ejit_arg){
-			.i64 = ejit_run_func_i(f, argc, args),
+			.l = ejit_run_func_i(f, argc, args),
 			.type = f->rtype
 		};
 	}
diff --git a/src/interp.c b/src/interp.c
index 2d9b7c7..049498a 100644
--- a/src/interp.c
+++ b/src/interp.c
@@ -984,7 +984,18 @@ union interp_ret ejit_run(struct ejit_func *f, size_t paramc, struct ejit_arg pa
 	DISPATCH();
 
 	DO(PARAM);
-	gpr[i.r2] = params[i.r0].u64;
+	switch (i.r1) {
+	case EJIT_INT8:    gpr[i.r2] = params[i.r0].i8; break;
+	case EJIT_INT16:   gpr[i.r2] = params[i.r0].i16; break;
+	case EJIT_INT32:   gpr[i.r2] = params[i.r0].i32; break;
+	case EJIT_INT64:   gpr[i.r2] = params[i.r0].i64; break;
+	case EJIT_UINT8:   gpr[i.r2] = params[i.r0].u8; break;
+	case EJIT_UINT16:  gpr[i.r2] = params[i.r0].u16; break;
+	case EJIT_UINT32:  gpr[i.r2] = params[i.r0].u32; break;
+	case EJIT_UINT64:  gpr[i.r2] = params[i.r0].u64; break;
+	case EJIT_POINTER: gpr[i.r2] = (int64_t)params[i.r0].p; break;
+	default: abort();
+	}
 	DISPATCH();
 
 	DO(PARAM_F);
diff --git a/tests/escapei_10.c b/tests/escapei_10.c
index 4ae00b8..ec48df0 100644
--- a/tests/escapei_10.c
+++ b/tests/escapei_10.c
@@ -21,26 +21,16 @@ static int32_t func(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e,
 static long escape_func(size_t argc, const struct ejit_arg args[argc])
 {
 	assert(argc == 10);
-	assert(args[0].type == EJIT_INT32);
-	assert(args[1].type == EJIT_INT32);
-	assert(args[3].type == EJIT_INT32);
-	assert(args[4].type == EJIT_INT32);
-	assert(args[5].type == EJIT_INT32);
-	assert(args[6].type == EJIT_INT32);
-	assert(args[7].type == EJIT_INT32);
-	assert(args[8].type == EJIT_INT32);
-	assert(args[9].type == EJIT_INT32);
-
-	int32_t a = args[0].i32;
-	int32_t b = args[1].i32;
-	int32_t c = args[2].i32;
-	int32_t d = args[3].i32;
-	int32_t e = args[4].i32;
-	int32_t f = args[5].i32;
-	int32_t g = args[6].i32;
-	int32_t h = args[7].i32;
-	int32_t i = args[8].i32;
-	int32_t j = args[9].i32;
+	int32_t a = EJIT_PARAM(argc, args, 0, int32_t);
+	int32_t b = EJIT_PARAM(argc, args, 1, int32_t);
+	int32_t c = EJIT_PARAM(argc, args, 2, int32_t);
+	int32_t d = EJIT_PARAM(argc, args, 3, int32_t);
+	int32_t e = EJIT_PARAM(argc, args, 4, int32_t);
+	int32_t f = EJIT_PARAM(argc, args, 5, int32_t);
+	int32_t g = EJIT_PARAM(argc, args, 6, int32_t);
+	int32_t h = EJIT_PARAM(argc, args, 7, int32_t);
+	int32_t i = EJIT_PARAM(argc, args, 8, int32_t);
+	int32_t j = EJIT_PARAM(argc, args, 9, int32_t);
 	return func(a, b, c, d, e, f, g, h, i, j);
 }
 
diff --git a/tests/escapei_double.c b/tests/escapei_double.c
index 6ea9f90..736e978 100644
--- a/tests/escapei_double.c
+++ b/tests/escapei_double.c
@@ -9,10 +9,8 @@ static double func(int32_t a, double b) {
 static double escape_func(size_t argc, const struct ejit_arg args[argc])
 {
 	assert(argc == 2);
-	assert(args[0].type == EJIT_INT32);
-	assert(args[1].type == EJIT_DOUBLE);
-	int32_t a = args[0].i32;
-	double b = args[1].d;
+	int32_t a = EJIT_PARAM(argc, args, 0, int32_t);
+	double b = EJIT_PARAM(argc, args, 1, double);
 	return func(a, b);
 }
 
diff --git a/tests/escapei_float.c b/tests/escapei_float.c
index 7a1b923..7cdc30d 100644
--- a/tests/escapei_float.c
+++ b/tests/escapei_float.c
@@ -9,10 +9,8 @@ static float func(int32_t a, float b) {
 static float escape_func(size_t argc, const struct ejit_arg args[argc])
 {
 	assert(argc == 2);
-	assert(args[0].type == EJIT_INT32);
-	assert(args[1].type == EJIT_FLOAT);
-	int32_t a = args[0].i32;
-	float b = args[1].f;
+	int32_t a = EJIT_PARAM(argc, args, 0, int32_t);
+	float b = EJIT_PARAM(argc, args, 1, float);
 	return func(a, b);
 }
 
diff --git a/tests/escapei_immediate_10.c b/tests/escapei_immediate_10.c
index 381c79f..5517c35 100644
--- a/tests/escapei_immediate_10.c
+++ b/tests/escapei_immediate_10.c
@@ -21,26 +21,16 @@ static int32_t func(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e,
 static long escape_func(size_t argc, const struct ejit_arg args[argc])
 {
 	assert(argc == 10);
-	assert(args[0].type == EJIT_INT32);
-	assert(args[1].type == EJIT_INT32);
-	assert(args[3].type == EJIT_INT32);
-	assert(args[4].type == EJIT_INT32);
-	assert(args[5].type == EJIT_INT32);
-	assert(args[6].type == EJIT_INT32);
-	assert(args[7].type == EJIT_INT32);
-	assert(args[8].type == EJIT_INT32);
-	assert(args[9].type == EJIT_INT32);
-
-	int32_t a = args[0].i32;
-	int32_t b = args[1].i32;
-	int32_t c = args[2].i32;
-	int32_t d = args[3].i32;
-	int32_t e = args[4].i32;
-	int32_t f = args[5].i32;
-	int32_t g = args[6].i32;
-	int32_t h = args[7].i32;
-	int32_t i = args[8].i32;
-	int32_t j = args[9].i32;
+	int32_t a = EJIT_PARAM(argc, args, 0, int32_t);
+	int32_t b = EJIT_PARAM(argc, args, 1, int32_t);
+	int32_t c = EJIT_PARAM(argc, args, 2, int32_t);
+	int32_t d = EJIT_PARAM(argc, args, 3, int32_t);
+	int32_t e = EJIT_PARAM(argc, args, 4, int32_t);
+	int32_t f = EJIT_PARAM(argc, args, 5, int32_t);
+	int32_t g = EJIT_PARAM(argc, args, 6, int32_t);
+	int32_t h = EJIT_PARAM(argc, args, 7, int32_t);
+	int32_t i = EJIT_PARAM(argc, args, 8, int32_t);
+	int32_t j = EJIT_PARAM(argc, args, 9, int32_t);
 	return func(a, b, c, d, e, f, g, h, i, j);
 }
 
-- 
cgit v1.2.3