diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-03-14 21:08:01 +0200 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-03-14 21:08:01 +0200 |
commit | f5c729ea59d227a507f83bd94d07f4366b46d72b (patch) | |
tree | 70d1f242100cea09acd38a71ff8c821836117cfd /src/ejit.c | |
parent | 57f6b41047e95374701ee276248f0f8615168450 (diff) | |
download | ejit-f5c729ea59d227a507f83bd94d07f4366b46d72b.tar.gz ejit-f5c729ea59d227a507f83bd94d07f4366b46d72b.zip |
start supporting 32bit arches
Diffstat (limited to 'src/ejit.c')
-rw-r--r-- | src/ejit.c | 248 |
1 files changed, 196 insertions, 52 deletions
@@ -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; |