From 6824dd4b1ee22184f0e600115db3998924ed39d6 Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Wed, 9 Apr 2025 19:56:33 +0300
Subject: initial tail call stuff

---
 src/ejit.c | 79 ++++++++++++++++++++++++--------------------------------------
 1 file changed, 30 insertions(+), 49 deletions(-)

(limited to 'src/ejit.c')

diff --git a/src/ejit.c b/src/ejit.c
index 571a274..059d5d4 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -414,7 +414,7 @@ void ejit_select_compile_func(struct ejit_func *f, size_t gpr, size_t fpr,
 
 	void **labels;
 	/* just get labels, don't actually run anything yet */
-	ejit_run(f, 0, NULL, false, &labels);
+	ejit_run(f, 0, NULL, &labels);
 
 	foreach_vec(ii, f->insns) {
 		struct ejit_insn i = *insns_at(&f->insns, ii);
@@ -456,67 +456,48 @@ void ejit_patch(struct ejit_func *f, struct ejit_reloc r, struct ejit_label l)
 	*insns_at(&f->insns, r.insn) = i;
 }
 
-void ejit_calli_i(struct ejit_func *s, struct ejit_func *f, size_t argc,
+void ejit_tailr(struct ejit_func *s, struct ejit_gpr target, size_t argc,
                 const struct ejit_operand args[argc])
 {
 	s->max_args = argc > s->max_args ? argc : s->max_args;
-	check_operands(f, argc, args);
 
+	/** @todo check that gpr_args <= 2 and fpr_args <= 3 (?) */
+	size_t gpr_args = 0, fpr_args = 0;
 	for (size_t i = 0; i < argc; ++i) {
 		switch (args[i].kind) {
-		case EJIT_OPERAND_GPR: emit_insn_ar(s, EJIT_OP_ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
-		case EJIT_OPERAND_FPR: emit_insn_af(s, EJIT_OP_ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
-		case EJIT_OPERAND_IMM: emit_insn_ai(s, EJIT_OP_ARG_I, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FLT: emit_insn_ad(s, EJIT_OP_ARG_FI, i, args[i].type, args[i].d); break;
-		default: abort();
-		}
-	}
-
-	emit_insn_op(s, EJIT_OP_CALLI_I, f);
-}
-
-void ejit_calli_l(struct ejit_func *s, struct ejit_func *f, size_t argc,
-                const struct ejit_operand args[argc])
-{
-	s->use_64 = true;
-	s->max_args = argc > s->max_args ? argc : s->max_args;
-	check_operands(f, argc, args);
+		case EJIT_OPERAND_GPR:
+			gpr_args++;
+			emit_insn_ar(s, EJIT_OP_ARG, i, args[i].type, EJIT_GPR(args[i].r));
+			break;
 
-	for (size_t i = 0; i < argc; ++i) {
-		switch (args[i].kind) {
-		case EJIT_OPERAND_GPR: emit_insn_ar(s, EJIT_OP_ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
-		case EJIT_OPERAND_FPR: emit_insn_af(s, EJIT_OP_ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
-		case EJIT_OPERAND_IMM: emit_insn_ai(s, EJIT_OP_ARG_I, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FLT: emit_insn_ad(s, EJIT_OP_ARG_FI, i, args[i].type, args[i].d); break;
-		default: abort();
-		}
-	}
+		case EJIT_OPERAND_FPR:
+			fpr_args++;
+			emit_insn_af(s, EJIT_OP_ARG_F, i, args[i].type, EJIT_FPR(args[i].r));
+			break;
 
-	emit_insn_op(s, EJIT_OP_CALLI_L, f);
-}
+		case EJIT_OPERAND_IMM:
+			gpr_args++;
+			emit_insn_ai(s, EJIT_OP_ARG_I, i, args[i].type, args[i].r);
+			break;
 
-void ejit_calli_f(struct ejit_func *s, struct ejit_func *f, size_t argc,
-                const struct ejit_operand args[argc])
-{
-	s->max_args = argc > s->max_args ? argc : s->max_args;
-	check_operands(f, argc, args);
+		case EJIT_OPERAND_FLT:
+			fpr_args++;
+			emit_insn_ad(s, EJIT_OP_ARG_FI, i, args[i].type, args[i].d);
+			break;
 
-	for (size_t i = 0; i < argc; ++i) {
-		switch (args[i].kind) {
-		case EJIT_OPERAND_GPR: emit_insn_ar(s, EJIT_OP_ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
-		case EJIT_OPERAND_FPR: emit_insn_af(s, EJIT_OP_ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
-		case EJIT_OPERAND_IMM: emit_insn_ai(s, EJIT_OP_ARG_I, i, args[i].type, args[i].r); break;
-		case EJIT_OPERAND_FLT: emit_insn_ad(s, EJIT_OP_ARG_FI, i, args[i].type, args[i].d); break;
 		default: abort();
 		}
 	}
 
-	emit_insn_op(s, EJIT_OP_CALLI_F, f);
+	assert(gpr_args <= 2 && fpr_args == 0
+			&& "only 2 gpr args and 0 fpr args supported in tail calls for now");
+	emit_insn_oxr(s, EJIT_OP_TAILR, target);
 }
 
-void ejit_calli_d(struct ejit_func *s, struct ejit_func *f, size_t argc,
+void ejit_calli(struct ejit_func *s, struct ejit_func *f, size_t argc,
                 const struct ejit_operand args[argc])
 {
+	s->use_64 = f->rtype == EJIT_INT64 || f->rtype == EJIT_UINT64;
 	s->max_args = argc > s->max_args ? argc : s->max_args;
 	check_operands(f, argc, args);
 
@@ -530,7 +511,7 @@ void ejit_calli_d(struct ejit_func *s, struct ejit_func *f, size_t argc,
 		}
 	}
 
-	emit_insn_op(s, EJIT_OP_CALLI_D, f);
+	emit_insn_op(s, EJIT_OP_CALLI, f);
 }
 
 void ejit_escapei_i(struct ejit_func *s, ejit_escape_i_t f, size_t argc,
@@ -1712,7 +1693,7 @@ long ejit_run_func_i(struct ejit_func *f, size_t argc,
 #endif
 		);
 
-	return ejit_run(f, argc, args, true, NULL).i;
+	return ejit_run(f, argc, args, NULL).i;
 }
 
 int64_t ejit_run_func_l(struct ejit_func *f, size_t argc,
@@ -1720,21 +1701,21 @@ int64_t ejit_run_func_l(struct ejit_func *f, size_t argc,
 {
 	check_args(f, argc, args);
 	assert(f->rtype == EJIT_INT64 || f->rtype == EJIT_UINT64);
-	return ejit_run(f, argc, args, true, NULL).i;
+	return ejit_run(f, argc, args, NULL).i;
 }
 
 float ejit_run_func_f(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
 {
 	check_args(f, argc, args);
 	assert(f->rtype == EJIT_FLOAT);
-	return ejit_run(f, argc, args, true, NULL).f;
+	return ejit_run(f, argc, args, NULL).f;
 }
 
 double ejit_run_func_d(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
 {
 	check_args(f, argc, args);
 	assert(f->rtype == EJIT_DOUBLE);
-	return ejit_run(f, argc, args, true, NULL).f;
+	return ejit_run(f, argc, args, NULL).f;
 }
 
 struct ejit_arg ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
-- 
cgit v1.2.3