aboutsummaryrefslogtreecommitdiff
path: root/src/ejit.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-03-14 21:08:01 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2025-03-14 21:08:01 +0200
commitf5c729ea59d227a507f83bd94d07f4366b46d72b (patch)
tree70d1f242100cea09acd38a71ff8c821836117cfd /src/ejit.c
parent57f6b41047e95374701ee276248f0f8615168450 (diff)
downloadejit-f5c729ea59d227a507f83bd94d07f4366b46d72b.tar.gz
ejit-f5c729ea59d227a507f83bd94d07f4366b46d72b.zip
start supporting 32bit arches
Diffstat (limited to 'src/ejit.c')
-rw-r--r--src/ejit.c248
1 files changed, 196 insertions, 52 deletions
diff --git a/src/ejit.c b/src/ejit.c
index b0a0d51..660d476 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -1,4 +1,3 @@
-#include <math.h>
#include <assert.h>
#include <sys/mman.h>
@@ -6,6 +5,22 @@
#include "common.h"
+static void check_operands(struct ejit_func *f, size_t argc, const struct ejit_operand args[argc])
+{
+ assert(argc == types_len(&f->sign));
+ for (size_t i = 0; i < types_len(&f->sign); ++i) {
+ assert(args[i].type == *types_at(&f->sign, i));
+ }
+}
+
+static void check_args(struct ejit_func *f, size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == types_len(&f->sign));
+ for (size_t i = 0; i < types_len(&f->sign); ++i) {
+ assert(args[i].type == *types_at(&f->sign, i));
+ }
+}
+
static struct gpr_stat zero_gpr_stat()
{
return (struct gpr_stat){
@@ -314,6 +329,7 @@ struct ejit_func *ejit_create_func(enum ejit_type rtype, size_t argc,
f->rtype = rtype;
+ f->sign = types_create();
f->insns = insns_create();
f->labels = labels_create();
f->gpr = gpr_stats_create();
@@ -325,6 +341,8 @@ struct ejit_func *ejit_create_func(enum ejit_type rtype, size_t argc,
f->use_64 = false;
for (size_t i = 0; i < argc; ++i) {
+ types_append(&f->sign, args[i].type);
+
switch (args[i].kind) {
case EJIT_OPERAND_GPR: {
assert(ejit_int_type(args[i].type));
@@ -373,10 +391,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 */
- if (ejit_float_type(f->rtype))
- ejit_run_interp_f(f, 0, NULL, NULL, false, &labels);
- else
- ejit_run_interp(f, 0, NULL, NULL, false, &labels);
+ ejit_run(f, 0, NULL, NULL, false, &labels);
foreach_vec(ii, f->insns) {
struct ejit_insn i = *insns_at(&f->insns, ii);
@@ -395,6 +410,7 @@ void ejit_destroy_func(struct ejit_func *f)
if (f->arena)
munmap(f->arena, f->size);
+ types_destroy(&f->sign);
insns_destroy(&f->insns);
labels_destroy(&f->labels);
gpr_stats_destroy(&f->gpr);
@@ -417,9 +433,82 @@ 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(struct ejit_func *s, struct ejit_func *f, size_t argc,
+void ejit_calli_i(struct ejit_func *s, struct ejit_func *f, size_t argc,
+ const struct ejit_operand args[argc])
+{
+ check_operands(f, argc, args);
+
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_ar(s, ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
+ case EJIT_OPERAND_FPR: emit_insn_af(s, ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
+ case EJIT_OPERAND_IMM: emit_insn_ai(s, ARG_I, i, args[i].type, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_ad(s, ARG_FI, i, args[i].type, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_op(s, 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;
+ check_operands(f, argc, args);
+
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_ar(s, ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
+ case EJIT_OPERAND_FPR: emit_insn_af(s, ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
+ case EJIT_OPERAND_IMM: emit_insn_ai(s, ARG_I, i, args[i].type, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_ad(s, ARG_FI, i, args[i].type, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_op(s, CALLI_L, f);
+}
+
+void ejit_calli_f(struct ejit_func *s, struct ejit_func *f, size_t argc,
const struct ejit_operand args[argc])
{
+ check_operands(f, argc, args);
+
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_ar(s, ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
+ case EJIT_OPERAND_FPR: emit_insn_af(s, ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
+ case EJIT_OPERAND_IMM: emit_insn_ai(s, ARG_I, i, args[i].type, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_ad(s, ARG_FI, i, args[i].type, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_op(s, CALLI_F, f);
+}
+
+void ejit_calli_d(struct ejit_func *s, struct ejit_func *f, size_t argc,
+ const struct ejit_operand args[argc])
+{
+ check_operands(f, argc, args);
+
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR: emit_insn_ar(s, ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
+ case EJIT_OPERAND_FPR: emit_insn_af(s, ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
+ case EJIT_OPERAND_IMM: emit_insn_ai(s, ARG_I, i, args[i].type, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_ad(s, ARG_FI, i, args[i].type, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_op(s, CALLI_D, f);
+}
+
+void ejit_escapei_i(struct ejit_func *s, ejit_escape_i_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_ar(s, ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
@@ -430,12 +519,13 @@ void ejit_calli(struct ejit_func *s, struct ejit_func *f, size_t argc,
}
}
- emit_insn_op(s, CALLI, f);
+ emit_insn_op(s, ESCAPEI_I, f);
}
-void ejit_escapei(struct ejit_func *s, ejit_escape_t f, size_t argc,
+void ejit_escapei_l(struct ejit_func *s, ejit_escape_l_t f, size_t argc,
const struct ejit_operand args[argc])
{
+ s->use_64 = true;
for (size_t i = 0; i < argc; ++i) {
switch (args[i].kind) {
case EJIT_OPERAND_GPR: emit_insn_ar(s, ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
@@ -446,7 +536,7 @@ void ejit_escapei(struct ejit_func *s, ejit_escape_t f, size_t argc,
}
}
- emit_insn_op(s, ESCAPEI, f);
+ emit_insn_op(s, ESCAPEI_L, f);
}
void ejit_escapei_f(struct ejit_func *s, ejit_escape_f_t f, size_t argc,
@@ -465,6 +555,22 @@ void ejit_escapei_f(struct ejit_func *s, ejit_escape_f_t f, size_t argc,
emit_insn_op(s, ESCAPEI_F, f);
}
+void ejit_escapei_d(struct ejit_func *s, ejit_escape_d_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_ar(s, ARG, i, args[i].type, EJIT_GPR(args[i].r)); break;
+ case EJIT_OPERAND_FPR: emit_insn_af(s, ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); break;
+ case EJIT_OPERAND_IMM: emit_insn_ai(s, ARG_I, i, args[i].type, args[i].r); break;
+ case EJIT_OPERAND_FLT: emit_insn_ad(s, ARG_FI, i, args[i].type, args[i].d); break;
+ default: abort();
+ }
+ }
+
+ emit_insn_op(s, ESCAPEI_D, f);
+}
+
void ejit_retval(struct ejit_func *s, struct ejit_gpr r0)
{
emit_insn_or(s, RETVAL, r0);
@@ -617,11 +723,13 @@ void ejit_ldi_u16(struct ejit_func *s, struct ejit_gpr r0, void *p)
void ejit_ldi_u32(struct ejit_func *s, struct ejit_gpr r0, void *p)
{
+ s->use_64 = true;
emit_insn_orp(s, LDIU32, r0, p);
}
void ejit_ldi_u64(struct ejit_func *s, struct ejit_gpr r0, void *p)
{
+ s->use_64 = true;
emit_insn_orp(s, LDIU64, r0, p);
}
@@ -802,6 +910,7 @@ void ejit_extr_16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
void ejit_extr_32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
{
+ s->use_64 = true;
emit_insn_orr(s, EXTR32, r0, r1);
}
@@ -817,6 +926,7 @@ void ejit_extr_u16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
void ejit_extr_u32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
{
+ s->use_64 = true;
emit_insn_orr(s, EXTRU32, r0, r1);
}
@@ -883,7 +993,7 @@ void ejit_subr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1,
}
void ejit_subi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
- long o)
+ int64_t o)
{
emit_insn_orri(s, SUBI, r0, r1, o);
}
@@ -1541,71 +1651,105 @@ static void destroy_interp_state(struct interp_state state)
args_destroy(&state.args);
}
-int64_t ejit_run_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_func_ctx_i(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx)
{
- if (run) {
- assert(f->size && "trying to run a function that hasn't been compiled");
- assert(f->rtype == EJIT_VOID || ejit_int_type(f->rtype));
- if (f->arena)
- return ((ejit_escape_t)f->arena)(argc, args);
- }
+ check_args(f, argc, args);
+ assert((f->rtype == EJIT_VOID || ejit_int_type(f->rtype))
+#if __WORDSIZE != 64
+ && f->rtype != EJIT_INT64 && f->rtype != EJIT_UINT64
+#endif
+ );
- int64_t retval = 0; double retval_f = 0.0;
-#include "interp.inc"
- return retval;
+ return ejit_run(f, argc, args, ctx, true, NULL).i;
}
-double ejit_run_interp_f(struct ejit_func *f, size_t argc,
- struct ejit_arg args[argc],
- struct interp_state *state,
- bool run,
- void ***labels_wb)
+long ejit_run_func_i(struct ejit_func *f, size_t argc,
+ struct ejit_arg args[argc])
{
- if (run) {
- assert(f->size && "trying to run a function that hasn't been compiled");
- /* void functions should use ejit_run_interp */
- assert(ejit_float_type(f->rtype));
- if (f->arena)
- return ((ejit_escape_f_t)f->arena)(argc, args);
- }
+ struct interp_state state = create_interp_state();
+ long r = ejit_run_func_ctx_i(f, argc, args, &state);
+ destroy_interp_state(state);
+ return r;
+}
- int64_t retval = 0; double retval_f = 0.0;
-#include "interp.inc"
- return retval_f;
+int64_t ejit_run_func_ctx_l(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx)
+{
+ check_args(f, argc, args);
+ assert(f->rtype == EJIT_INT64 || f->rtype == EJIT_UINT64);
+ return ejit_run(f, argc, args, ctx, true, NULL).i;
}
-int64_t ejit_run_func(struct ejit_func *f, size_t argc,
+int64_t ejit_run_func_l(struct ejit_func *f, size_t argc,
struct ejit_arg args[argc])
{
- assert(f->size && "trying to run a function that hasn't been compiled");
- assert(f->rtype == EJIT_VOID || ejit_int_type(f->rtype));
- if (f->arena)
- return (int64_t)((ejit_escape_t)f->arena)(argc, args);
-
struct interp_state state = create_interp_state();
- long r = ejit_run_interp(f, argc, args, &state, true, NULL);
+ int64_t r = ejit_run_func_ctx_l(f, argc, args, &state);
destroy_interp_state(state);
return r;
}
-double ejit_run_func_f(struct ejit_func *f, size_t argc,
+float ejit_run_func_ctx_f(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx)
+{
+ check_args(f, argc, args);
+ assert(f->rtype == EJIT_FLOAT);
+ return ejit_run(f, argc, args, ctx, true, NULL).f;
+}
+
+float ejit_run_func_f(struct ejit_func *f, size_t argc,
struct ejit_arg args[argc])
{
- assert(f->size && "trying to run a function that hasn't been compiled");
- assert(ejit_float_type(f->rtype));
- if (f->arena)
- return ((ejit_escape_f_t)f->arena)(argc, args);
+ struct interp_state state = create_interp_state();
+ float r = ejit_run_func_ctx_f(f, argc, args, &state);
+ destroy_interp_state(state);
+ return r;
+}
+
+double ejit_run_func_ctx_d(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx)
+{
+ check_args(f, argc, args);
+ assert(f->rtype == EJIT_DOUBLE);
+ return ejit_run(f, argc, args, ctx, true, NULL).f;
+}
+double ejit_run_func_d(struct ejit_func *f, size_t argc,
+ struct ejit_arg args[argc])
+{
struct interp_state state = create_interp_state();
- double r = ejit_run_interp_f(f, argc, args, &state, true, NULL);
+ double r = ejit_run_func_ctx_d(f, argc, args, &state);
destroy_interp_state(state);
return r;
}
+struct ejit_arg ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
+{
+ switch (f->rtype) {
+ case EJIT_DOUBLE:
+ return (struct ejit_arg){
+ .d = ejit_run_func_d(f, argc, args),
+ .type = EJIT_DOUBLE
+ };
+
+ case EJIT_FLOAT:
+ return (struct ejit_arg){
+ .f = ejit_run_func_f(f, argc, args),
+ .type = EJIT_FLOAT
+ };
+
+ case EJIT_UINT64:
+ case EJIT_INT64:
+ return (struct ejit_arg){
+ .i64 = ejit_run_func_l(f, argc, args),
+ .type = f->rtype
+ };
+
+ default:
+ return (struct ejit_arg){
+ .i64 = ejit_run_func_i(f, argc, args),
+ .type = f->rtype
+ };
+ }
+}
+
size_t ejit_get_prio(struct ejit_func *s)
{
return s->prio;