diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-04-10 22:23:08 +0300 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-04-10 22:23:08 +0300 |
commit | 7628ce2432108ae6306457f242e7cc3ac75b9ac0 (patch) | |
tree | 32a7b59f0e91b4c82bdeb4de3f75c1a04cc247da | |
parent | 0ba52d9043985baff61d4fae225420274d9ad9ab (diff) | |
parent | 531d307d310881e69efc8ae8c8119f5f5799e0f9 (diff) | |
download | ejit-7628ce2432108ae6306457f242e7cc3ac75b9ac0.tar.gz ejit-7628ce2432108ae6306457f242e7cc3ac75b9ac0.zip |
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 127 | ||||
m--------- | deps/lightening | 0 | ||||
-rw-r--r-- | examples/fib.c | 4 | ||||
-rw-r--r-- | examples/sum.c | 78 | ||||
-rw-r--r-- | include/ejit/ejit.h | 196 | ||||
-rwxr-xr-x | scripts/gen-tests | 4 | ||||
-rw-r--r-- | scripts/makefile | 24 | ||||
-rwxr-xr-x | scripts/select-compile | 5 | ||||
-rw-r--r-- | src/common.h | 444 | ||||
-rw-r--r-- | src/compile/compile.c | 1115 | ||||
-rw-r--r-- | src/ejit.c | 706 | ||||
-rw-r--r-- | src/interp.c | 657 | ||||
-rw-r--r-- | tests/calli.c | 41 | ||||
-rw-r--r-- | tests/callr_i.c | 42 | ||||
-rw-r--r-- | tests/escapei_10.c | 30 | ||||
-rw-r--r-- | tests/escapei_double.c | 6 | ||||
-rw-r--r-- | tests/escapei_float.c | 6 | ||||
-rw-r--r-- | tests/escapei_immediate_10.c | 63 | ||||
-rw-r--r-- | tests/makefile | 44 | ||||
-rw-r--r-- | tests/maxr_d.c | 28 | ||||
-rw-r--r-- | tests/maxr_f.c | 28 | ||||
-rw-r--r-- | tests/minr_d.c | 28 | ||||
-rw-r--r-- | tests/minr_f.c | 28 | ||||
-rw-r--r-- | tests/sqrtr_d.c | 23 | ||||
-rw-r--r-- | tests/sqrtr_f.c | 23 | ||||
-rw-r--r-- | tests/taili.c | 39 | ||||
-rw-r--r-- | tests/tailr.c | 41 |
28 files changed, 2588 insertions, 1243 deletions
@@ -7,4 +7,5 @@ test-* examples/matrix_mult examples/loop examples/fib +examples/sum examples/*.d @@ -12,16 +12,121 @@ check: all @./scripts/gen-tests $$(echo tests/*.c) $(MAKE) -f tests/makefile check -# this kicks all unrecognised targets to the client script. -# note that trying to compile individual files, e.g. -# -# make kernel.elf -# -# will not work, you would need -# -# make -f scripts/makefile kernel.elf -# -# instead +# supported by jit +.PHONY: check_linux_amd64 +check_linux_amd64: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/x86_64-linux-gnu \ + $(MAKE) ARCH=amd64 CROSS_COMPILE=x86_64-linux-gnu- check + +.PHONY: check_linux_x86 +check_linux_x86: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/i686-linux-gnu \ + $(MAKE) ARCH=x86 CROSS_COMPILE=i686-linux-gnu- check + +.PHONY: check_linux_aarch64 +check_linux_aarch64: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ + $(MAKE) ARCH=aarch64 CROSS_COMPILE=aarch64-linux-gnu- check + +.PHONY: check_linux_armhf +check_linux_armhf: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + $(MAKE) ARCH=armhf CROSS_COMPILE=arm-linux-gnueabihf- check + +.PHONY: check_linux_powerpc64le +check_linux_powerpc64le: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ + $(MAKE) ARCH=powerpc64le CROSS_COMPILE=powerpc64le-linux-gnu- check + +# note: older than revision 6 +.PHONY: check_linux_mips64el +check_linux_mips64el: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ + $(MAKE) ARCH=mips64el CROSS_COMPILE=mips64el-linux-gnuabi64- check + +.PHONY: check_linux_mipsel +check_linux_mipsel: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ + $(MAKE) ARCH=mipsel CROSS_COMPILE=mipsel-linux-gnu- check + +# not supported by jit atm +.PHONY: check_linux_powerpc64 +check_linux_powerpc64: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ + $(MAKE) ARCH=powerpc64 CROSS_COMPILE=powerpc64-linux-gnu- check + +.PHONY: check_linux_powerpc +check_linux_powerpc: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ + $(MAKE) ARCH=powerpc CROSS_COMPILE=powerpc-linux-gnu- check + +.PHONY: check_linux_sparc64 +check_linux_sparc64: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/sparc64-linux-gnu \ + $(MAKE) ARCH=sparc64 CROSS_COMPILE=sparc64-linux-gnu- check + +.PHONY: check_linux_riscv64 +check_linux_riscv64: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ + $(MAKE) ARCH=riscv64 CROSS_COMPILE=riscv64-linux-gnu- check + +.PHONY: check_linux_s390x +check_linux_s390x: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/s390x-linux-gnu \ + $(MAKE) ARCH=s390x CROSS_COMPILE=s390x-linux-gnu- check + +.PHONY: check_linux_alpha +check_linux_alpha: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/alpha-linux-gnu \ + $(MAKE) ARCH=alpha CROSS_COMPILE=alpha-linux-gnu- check + +.PHONY: check_linux_hppa +check_linux_hppa: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/hppa-linux-gnu \ + $(MAKE) ARCH=hppa CROSS_COMPILE=hppa-linux-gnu- check + +.PHONY: check_linux_m68k +check_linux_m68k: + $(MAKE) clean + QEMU_LD_PREFIX=/usr/m68k-linux-gnu \ + $(MAKE) ARCH=m68k CROSS_COMPILE=m68k-linux-gnu- check + +.PHONY: check_linux +check_linux: + $(MAKE) check_linux_amd64 + $(MAKE) check_linux_x86 + $(MAKE) check_linux_aarch64 + $(MAKE) check_linux_armhf + $(MAKE) check_linux_powerpc64le + $(MAKE) check_linux_mips64el + $(MAKE) check_linux_mipsel + $(MAKE) check_linux_powerpc64 + $(MAKE) check_linux_powerpc + $(MAKE) check_linux_sparc64 + $(MAKE) check_linux_riscv64 + $(MAKE) check_linux_s390x + $(MAKE) check_linux_alpha + $(MAKE) check_linux_hppa + $(MAKE) check_linux_m68k + # compiler+emulator not available or broken + #$(MAKE) check_linux_hppa64 + #$(MAKE) check_linux_arc + #$(MAKE) check_linux_sh4 + .DEFAULT: setup $(MAKE) -f scripts/makefile $< @@ -30,7 +135,7 @@ setup: @echo -n > deps.mk @./scripts/gen-deps -p EJIT -c COMPILE_EJIT -b ejit "$(EJIT_SOURCES)" -CLEANUP := build deps.mk tests.md ejit.o examples/fib examples/loop \ +CLEANUP := build deps.mk tests.md libejit.a examples/fib examples/loop \ examples/*.d tests/test-* CLEANUP_CMD := EJIT_SOURCES := diff --git a/deps/lightening b/deps/lightening -Subproject 1cc7a2d159d8cbfc46708d24bfe49f6c23c6e44 +Subproject 3f4127c3ef16177be55cf6153a206ca4f8a4859 diff --git a/examples/fib.c b/examples/fib.c index 999546b..fcb0659 100644 --- a/examples/fib.c +++ b/examples/fib.c @@ -20,12 +20,12 @@ struct ejit_func *compile(bool try_jit, bool im_scawed) struct ejit_operand arg[1] = { EJIT_OPERAND_GPR(0, EJIT_INT32) }; - ejit_calli_i(f, f, 1, arg); + ejit_calli(f, f, 1, arg); ejit_retval(f, EJIT_GPR(1)); /* loc 1 contains temp result */ /* fib(n - 2) */ ejit_subi(f, EJIT_GPR(0), EJIT_GPR(0), 1); - ejit_calli_i(f, f, 1, arg); + ejit_calli(f, f, 1, arg); ejit_retval(f, EJIT_GPR(0)); /* loc 0 now contains second temp result */ ejit_addr(f, EJIT_GPR(0), EJIT_GPR(0), EJIT_GPR(1)); /* add results */ diff --git a/examples/sum.c b/examples/sum.c new file mode 100644 index 0000000..cc8f54b --- /dev/null +++ b/examples/sum.c @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <time.h> + +#include "../include/ejit/ejit.h" + +struct ejit_func *compile(bool try_jit, bool im_scawed) +{ + struct ejit_operand params[2] = { + EJIT_OPERAND_GPR(0, EJIT_INT32), /* loc 0 contains s */ + EJIT_OPERAND_GPR(1, EJIT_INT32) /* loc 1 contains n */ + }; + struct ejit_func *f = ejit_create_func(EJIT_INT32, 2, params); + + /* n == 0, return s */ + struct ejit_reloc recurse = ejit_bnei(f, EJIT_GPR(1), 0); + ejit_retr(f, EJIT_GPR(0)); + ejit_patch(f, recurse, ejit_label(f)); + + /* s += n */ + ejit_addr(f, EJIT_GPR(0), EJIT_GPR(0), EJIT_GPR(1)); + + /* n -= 1 */ + ejit_subi(f, EJIT_GPR(1), EJIT_GPR(1), 1); + + struct ejit_operand args[2] = { + EJIT_OPERAND_GPR(0, EJIT_INT32), /* s */ + EJIT_OPERAND_GPR(1, EJIT_INT32) /* n */ + }; + + /* recurse */ + ejit_movi(f, EJIT_GPR(2), (uintptr_t)f); + ejit_tailr(f, EJIT_GPR(2), 2, args); + + ejit_select_compile_func(f, 3, 0, EJIT_USE64(uintptr_t), try_jit, im_scawed); + return f; +} + +int main(int argc, char *argv[]) +{ + if(argc != 4){ + fprintf(stderr, "Usage: %s compile_num loop_num jit\n", argv[0]); + return -1; + } + + int jit_level = strtoull(argv[3], 0, 0); + size_t compile_num = strtoull(argv[1], 0, 0); + struct ejit_func **info = calloc(compile_num, sizeof(struct ejit_func *)); + + clock_t t = clock(); + for(size_t i = 0; i < compile_num; ++i){ + info[i] = compile(jit_level > 0, jit_level > 1); + } + t = clock() - t; + + double compile_time_total = ((double)t) / CLOCKS_PER_SEC; + double compile_time_one = compile_time_total / compile_num; + printf("Compilation for n = %zu took %fs (1/%f).\n", + compile_num, compile_time_total, compile_time_one); + + size_t run_num = strtoull(argv[2], 0, 0); + t = clock(); + struct ejit_arg args[2] = { + (struct ejit_arg){.type = EJIT_INT32, .l = 0}, /* s */ + (struct ejit_arg){.type = EJIT_INT32, .l = run_num} /* n */ + }; + int32_t result = ejit_run_func_i(info[0], 2, args); + t = clock() - t; + + double run_time_total = ((double)t) / CLOCKS_PER_SEC; + printf("Running loop for n = %zu took %fs with res %ld\n", + run_num, run_time_total, (long)result); + + for(size_t i = 0; i < compile_num; ++i) + ejit_destroy_func(info[i]); + + free(info); + return 0; +} diff --git a/include/ejit/ejit.h b/include/ejit/ejit.h index 4ab2bbc..ab06d8f 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; }; @@ -113,6 +104,7 @@ static inline bool ejit_int_type(enum ejit_type t) case EJIT_POINTER: return true; default: + break; } return false; @@ -125,6 +117,7 @@ static inline bool ejit_float_type(enum ejit_type t) case EJIT_DOUBLE: return true; default: + break; } return false; @@ -136,15 +129,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(); } @@ -157,7 +150,7 @@ static inline struct ejit_arg ejit_build_arg_f(enum ejit_type type, double x) a.type = type; switch (type) { - case EJIT_FLOAT: a.f = x; break; + case EJIT_FLOAT: a.f = (float)x; break; case EJIT_DOUBLE: a.d = x; break; default: abort(); } @@ -223,21 +216,6 @@ double ejit_run_func_d(struct ejit_func *f, size_t argc, struct ejit_arg ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg args[argc]); - -/* currently unused, the idea is that an escape could get the interpreter state - * and pass it on to speed up entering/exiting the VM, could be useful for more - * dynamic languages */ -struct interp_state; - -long ejit_run_func_ctx_i(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx); - -int64_t ejit_run_func_ctx_l(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx); - -float ejit_run_func_ctx_f(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx); - -double ejit_run_func_ctx_d(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx); - - void ejit_destroy_func(struct ejit_func *s); #define EJIT_GPR(x) ((struct ejit_gpr){.r = (x)}) @@ -260,23 +238,23 @@ void ejit_destroy_func(struct ejit_func *s); .type = (t)}) #define EJIT_OPERAND_FLT(x, t) \ ((struct ejit_operand){ .kind = EJIT_OPERAND_FLT, \ - .r = (double)(x), \ + .d = (double)(x), \ .type = (t)}) /* 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) @@ -286,22 +264,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) @@ -387,6 +365,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) @@ -405,29 +454,39 @@ typedef double (*ejit_escape_d_t)(size_t argc, const struct ejit_arg args[argc]) struct ejit_label ejit_label(struct ejit_func *s); -void ejit_calli_i(struct ejit_func *s, struct ejit_func *f, size_t argc, - const struct ejit_operand args[argc]); +void ejit_tailr(struct ejit_func *s, struct ejit_gpr target, + size_t argc, const struct ejit_operand args[argc]); + +void ejit_taili(struct ejit_func *s, struct ejit_func *f, + size_t argc, const struct ejit_operand args[argc]); -void ejit_calli_l(struct ejit_func *s, struct ejit_func *f, size_t argc, - const struct ejit_operand args[argc]); +/* return type can be deduced */ +void ejit_calli(struct ejit_func *s, struct ejit_func *f, + size_t argc, const struct ejit_operand args[argc]); -void ejit_calli_f(struct ejit_func *s, struct ejit_func *f, size_t argc, - const struct ejit_operand args[argc]); +void ejit_callr_i(struct ejit_func *s, struct ejit_gpr target, + size_t argc, const struct ejit_operand args[argc]); -void ejit_calli_d(struct ejit_func *s, struct ejit_func *f, size_t argc, - const struct ejit_operand args[argc]); +void ejit_callr_l(struct ejit_func *s, struct ejit_gpr target, + size_t argc, const struct ejit_operand args[argc]); -void ejit_escapei_i(struct ejit_func *s, ejit_escape_i_t f, size_t argc, - const struct ejit_operand args[argc]); +void ejit_callr_f(struct ejit_func *s, struct ejit_gpr target, + size_t argc, const struct ejit_operand args[argc]); -void ejit_escapei_l(struct ejit_func *s, ejit_escape_l_t f, size_t argc, - const struct ejit_operand args[argc]); +void ejit_callr_d(struct ejit_func *s, struct ejit_gpr target, + 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]); +void ejit_escapei_i(struct ejit_func *s, ejit_escape_i_t f, + size_t argc, const struct ejit_operand args[argc]); -void ejit_escapei_d(struct ejit_func *s, ejit_escape_d_t f, size_t argc, - const struct ejit_operand args[argc]); +void ejit_escapei_l(struct ejit_func *s, ejit_escape_l_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]); + +void ejit_escapei_d(struct ejit_func *s, ejit_escape_d_t f, + size_t argc, const struct ejit_operand args[argc]); void ejit_ret(struct ejit_func *s); void ejit_retr(struct ejit_func *s, struct ejit_gpr r0); @@ -820,6 +879,15 @@ void ejit_truncr_d_32(struct ejit_func *s, struct ejit_gpr r0, void ejit_truncr_d_64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1); +void ejit_sqrtr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1); +void ejit_sqrtr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1); + +void ejit_minr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2); +void ejit_minr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2); + +void ejit_maxr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2); +void ejit_maxr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2); + struct ejit_reloc ejit_bltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1); struct ejit_reloc ejit_bner(struct ejit_func *s, struct ejit_gpr r0, diff --git a/scripts/gen-tests b/scripts/gen-tests index 5521006..47ff9c9 100755 --- a/scripts/gen-tests +++ b/scripts/gen-tests @@ -11,5 +11,7 @@ do echo "${dep}:" >> tests.mk echo "-include ${dep}" >> tests.mk echo "${exe}: ${s} libejit.a" >> tests.mk - echo " \$(COMPILE_TEST) ${s} libejit.a -o ${exe}" >> tests.mk + echo " \$(COMPILE_TEST) ${s} libejit.a -o ${exe} -lm" >> tests.mk + echo " ./${exe} \t# bytecode" >> tests.mk + echo " ./${exe} 1\t# jit" >> tests.mk done diff --git a/scripts/makefile b/scripts/makefile index 3a4f200..dbb7a1c 100644 --- a/scripts/makefile +++ b/scripts/makefile @@ -29,16 +29,21 @@ OBJCOPY != [ "$(LLVM)" != "0" ] \ && echo llvm-objcopy \ || echo $(CROSS_COMPILE)objcopy -COMPILER != [ "$(LLVM)" != "0" ] \ - && echo clang --target="$(CROSS_COMPILE)" \ - || echo $(CROSS_COMPILE)gcc +COMPILER != [ -n "$(CROSS_COMPILE)" ] \ + && { \ + [ "$(LLVM)" != "0" ] \ + && echo clang --target="$(CROSS_COMPILE)" \ + || echo $(CROSS_COMPILE)gcc \ + ; \ + } \ + || echo $(CC) OBFLAGS := -g WARNFLAGS := -Wall -Wextra COMPILE_FLAGS := $(CFLAGS) $(WARNFLAGS) $(OPTFLAGS) $(LTOFLAGS) \ - $(OBFLAGS) $(ASSERTFLAGS) $(DEBUGFLAGS) + $(OBFLAGS) $(DEBUGFLAGS) INCLUDE_FLAGS := -I include @@ -60,16 +65,19 @@ COMPILE_EJIT = $(COMPILE) $(EJIT_FLAGS) libejit.a: $(EJIT_OBJS) $(CROSS_COMPILE)ar rcs libejit.a $(EJIT_OBJS) -examples: examples/loop examples/fib examples/matrix_mult +examples: examples/loop examples/fib examples/sum examples/matrix_mult examples/matrix_mult: examples/matrix_mult.c libejit.a - $(COMPILE_EJIT) examples/matrix_mult.c libejit.a -o $@ + $(COMPILE_EJIT) examples/matrix_mult.c libejit.a -o $@ -lm examples/loop: examples/loop.c libejit.a - $(COMPILE_EJIT) examples/loop.c libejit.a -o $@ + $(COMPILE_EJIT) examples/loop.c libejit.a -o $@ -lm examples/fib: examples/fib.c libejit.a - $(COMPILE_EJIT) examples/fib.c libejit.a -o $@ + $(COMPILE_EJIT) examples/fib.c libejit.a -o $@ -lm + +examples/sum: examples/sum.c libejit.a + $(COMPILE_EJIT) examples/sum.c libejit.a -o $@ -lm # might lint some common things twice .PHONY: diff --git a/scripts/select-compile b/scripts/select-compile index fca7350..37c67a1 100755 --- a/scripts/select-compile +++ b/scripts/select-compile @@ -9,6 +9,11 @@ JIT="src/compile/compile.c" NOJIT="src/compile/nocompile.c" case "$ARCH" in + powerpc64le) echo "$JIT" ;; + mips64el) echo "$JIT" ;; + aarch64) echo "$JIT" ;; + mipsel) echo "$JIT" ;; + armhf) echo "$JIT" ;; amd64) echo "$JIT" ;; x86*) echo "$JIT" ;; *) echo "$NOJIT" ;; diff --git a/src/common.h b/src/common.h index 6ee0df7..dc970f0 100644 --- a/src/common.h +++ b/src/common.h @@ -21,214 +21,227 @@ #include "vec.h" enum ejit_opcode { - MOVI, - MOVI_F, - MOVI_D, - MOVR, - MOVR_F, - MOVR_D, - - LDI8, - LDI16, - LDI32, - LDI64, - LDIU8, - LDIU16, - LDIU32, - LDIU64, - LDIF, - LDID, - - LDXI8, - LDXI16, - LDXI32, - LDXI64, - LDXIU8, - LDXIU16, - LDXIU32, - LDXIU64, - LDXIF, - LDXID, - - LDXR8, - LDXR16, - LDXR32, - LDXR64, - LDXRU8, - LDXRU16, - LDXRU32, - LDXRU64, - LDXRF, - LDXRD, - - STI8, - STI16, - STI32, - STI64, - STIF, - STID, - - STXI8, - STXI16, - STXI32, - STXI64, - STXIF, - STXID, - - STXR8, - STXR16, - STXR32, - STXR64, - STXRF, - STXRD, - - EXTR8, - EXTR16, - EXTR32, - EXTRU8, - EXTRU16, - EXTRU32, - EXTRF, - EXTRD, - - ADDR, - ADDR_F, - ADDR_D, - ADDI, - - ABSR_F, - ABSR_D, - - SUBR, - SUBR_F, - SUBR_D, - SUBI, - - MULR, - MULR_F, - MULR_D, - - DIVR, - DIVR_U, - DIVR_F, - DIVR_D, - - REMR, - REMR_U, - - COMR, - NEGR, - NEGR_F, - NEGR_D, - - LSHI, - LSHR, - RSHI, - RSHI_U, - RSHR, - RSHR_U, - - ANDR, - ANDI, - - ORR, - ORI, - - XORR, - XORI, - - TRUNCR_D_32, - TRUNCR_D_64, - TRUNCR_F_32, - TRUNCR_F_64, - - EQR, - NER, - GTR, - GTR_U, - GER, - GER_U, - - EQR_F, - NER_F, - GTR_F, - GER_F, - EQR_D, - NER_D, - GTR_D, - GER_D, - - BNER, - BNEI, - BNER_F, - BNER_D, - - BEQR, - BEQI, - BEQR_F, - BEQR_D, - - BGER, - BGER_U, - BGEI, - BGEI_U, - BGER_F, - BGER_D, - - BLEI, - BLEI_U, - - BGTR, - BGTR_U, - BGTI, - BGTI_U, - BGTR_F, - BGTR_D, - - BLTI, - BLTI_U, - - JMP, - JMPR, - - BMCI, - BMCR, - BMSI, - BMSR, - - PARAM, - PARAM_F, - - ARG, - ARG_I, - ARG_F, - ARG_FI, - - ESCAPEI_I, - ESCAPEI_L, - ESCAPEI_F, - ESCAPEI_D, - - CALLI_I, - CALLI_L, - CALLI_F, - CALLI_D, - - RETR, - RETI, - RETR_F, - RETR_D, - RETI_F, - RETI_D, - - RETVAL, - RETVAL_F, - RETVAL_D, - - START, - END, - - OPCODE_COUNT, + EJIT_OP_MOVI, + EJIT_OP_MOVI_F, + EJIT_OP_MOVI_D, + EJIT_OP_MOVR, + EJIT_OP_MOVR_F, + EJIT_OP_MOVR_D, + + EJIT_OP_LDI8, + EJIT_OP_LDI16, + EJIT_OP_LDI32, + EJIT_OP_LDI64, + EJIT_OP_LDIU8, + EJIT_OP_LDIU16, + EJIT_OP_LDIU32, + EJIT_OP_LDIU64, + EJIT_OP_LDIF, + EJIT_OP_LDID, + + EJIT_OP_LDXI8, + EJIT_OP_LDXI16, + EJIT_OP_LDXI32, + EJIT_OP_LDXI64, + EJIT_OP_LDXIU8, + EJIT_OP_LDXIU16, + EJIT_OP_LDXIU32, + EJIT_OP_LDXIU64, + EJIT_OP_LDXIF, + EJIT_OP_LDXID, + + EJIT_OP_LDXR8, + EJIT_OP_LDXR16, + EJIT_OP_LDXR32, + EJIT_OP_LDXR64, + EJIT_OP_LDXRU8, + EJIT_OP_LDXRU16, + EJIT_OP_LDXRU32, + EJIT_OP_LDXRU64, + EJIT_OP_LDXRF, + EJIT_OP_LDXRD, + + EJIT_OP_STI8, + EJIT_OP_STI16, + EJIT_OP_STI32, + EJIT_OP_STI64, + EJIT_OP_STIF, + EJIT_OP_STID, + + EJIT_OP_STXI8, + EJIT_OP_STXI16, + EJIT_OP_STXI32, + EJIT_OP_STXI64, + EJIT_OP_STXIF, + EJIT_OP_STXID, + + EJIT_OP_STXR8, + EJIT_OP_STXR16, + EJIT_OP_STXR32, + EJIT_OP_STXR64, + EJIT_OP_STXRF, + EJIT_OP_STXRD, + + EJIT_OP_EXTR8, + EJIT_OP_EXTR16, + EJIT_OP_EXTR32, + EJIT_OP_EXTRU8, + EJIT_OP_EXTRU16, + EJIT_OP_EXTRU32, + EJIT_OP_EXTRF, + EJIT_OP_EXTRD, + + EJIT_OP_ADDR, + EJIT_OP_ADDR_F, + EJIT_OP_ADDR_D, + EJIT_OP_ADDI, + + EJIT_OP_ABSR_F, + EJIT_OP_ABSR_D, + + EJIT_OP_SUBR, + EJIT_OP_SUBR_F, + EJIT_OP_SUBR_D, + EJIT_OP_SUBI, + + EJIT_OP_MULR, + EJIT_OP_MULR_F, + EJIT_OP_MULR_D, + + EJIT_OP_DIVR, + EJIT_OP_DIVR_U, + EJIT_OP_DIVR_F, + EJIT_OP_DIVR_D, + + EJIT_OP_REMR, + EJIT_OP_REMR_U, + + EJIT_OP_COMR, + EJIT_OP_NEGR, + EJIT_OP_NEGR_F, + EJIT_OP_NEGR_D, + + EJIT_OP_LSHI, + EJIT_OP_LSHR, + EJIT_OP_RSHI, + EJIT_OP_RSHI_U, + EJIT_OP_RSHR, + EJIT_OP_RSHR_U, + + EJIT_OP_ANDR, + EJIT_OP_ANDI, + + EJIT_OP_ORR, + EJIT_OP_ORI, + + EJIT_OP_XORR, + EJIT_OP_XORI, + + EJIT_OP_TRUNCR_D_32, + EJIT_OP_TRUNCR_D_64, + EJIT_OP_TRUNCR_F_32, + EJIT_OP_TRUNCR_F_64, + + EJIT_OP_SQRTR_F, + EJIT_OP_SQRTR_D, + + EJIT_OP_MINR_F, + EJIT_OP_MINR_D, + + EJIT_OP_MAXR_F, + EJIT_OP_MAXR_D, + + EJIT_OP_EQR, + EJIT_OP_NER, + EJIT_OP_GTR, + EJIT_OP_GTR_U, + EJIT_OP_GER, + EJIT_OP_GER_U, + + EJIT_OP_EQR_F, + EJIT_OP_NER_F, + EJIT_OP_GTR_F, + EJIT_OP_GER_F, + EJIT_OP_EQR_D, + EJIT_OP_NER_D, + EJIT_OP_GTR_D, + EJIT_OP_GER_D, + + EJIT_OP_BNER, + EJIT_OP_BNEI, + EJIT_OP_BNER_F, + EJIT_OP_BNER_D, + + EJIT_OP_BEQR, + EJIT_OP_BEQI, + EJIT_OP_BEQR_F, + EJIT_OP_BEQR_D, + + EJIT_OP_BGER, + EJIT_OP_BGER_U, + EJIT_OP_BGEI, + EJIT_OP_BGEI_U, + EJIT_OP_BGER_F, + EJIT_OP_BGER_D, + + EJIT_OP_BLEI, + EJIT_OP_BLEI_U, + + EJIT_OP_BGTR, + EJIT_OP_BGTR_U, + EJIT_OP_BGTI, + EJIT_OP_BGTI_U, + EJIT_OP_BGTR_F, + EJIT_OP_BGTR_D, + + EJIT_OP_BLTI, + EJIT_OP_BLTI_U, + + EJIT_OP_JMP, + EJIT_OP_JMPR, + + EJIT_OP_BMCI, + EJIT_OP_BMCR, + EJIT_OP_BMSI, + EJIT_OP_BMSR, + + EJIT_OP_PARAM, + EJIT_OP_PARAM_F, + + EJIT_OP_ARG, + EJIT_OP_ARG_I, + EJIT_OP_ARG_F, + EJIT_OP_ARG_FI, + + EJIT_OP_ESCAPEI_I, + EJIT_OP_ESCAPEI_L, + EJIT_OP_ESCAPEI_F, + EJIT_OP_ESCAPEI_D, + + EJIT_OP_CALLR_I, + EJIT_OP_CALLR_L, + EJIT_OP_CALLR_F, + EJIT_OP_CALLR_D, + + EJIT_OP_CALLI, + EJIT_OP_TAILR, + EJIT_OP_TAILI, + + EJIT_OP_RETR, + EJIT_OP_RETI, + EJIT_OP_RETR_F, + EJIT_OP_RETR_D, + EJIT_OP_RETI_F, + EJIT_OP_RETI_D, + + EJIT_OP_RETVAL, + EJIT_OP_RETVAL_F, + EJIT_OP_RETVAL_D, + + EJIT_OP_START, + EJIT_OP_END, + + EJIT_OPCODE_COUNT, }; struct ejit_insn { @@ -258,7 +271,7 @@ struct ejit_insn { struct fpr_stat { struct ejit_fpr f; - size_t prio, fno; + size_t prio, fno, start, end; }; #define VEC_NAME fpr_stats @@ -267,7 +280,7 @@ struct fpr_stat { struct gpr_stat { struct ejit_gpr r; - size_t prio, rno; + size_t prio, rno, start, end; }; #define VEC_NAME gpr_stats @@ -286,15 +299,10 @@ struct ejit_func { void *arena; void *direct_call; + void *extern_call; size_t size; size_t prio; -}; - - -struct interp_state { - struct gprs gprs; - struct fprs fprs; - struct args args; + size_t max_args; }; union interp_ret { @@ -304,8 +312,6 @@ union interp_ret { union interp_ret ejit_run(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], - struct interp_state *state, - bool run, void ***labels_wb); bool ejit_compile(struct ejit_func *f, bool use_64, bool im_scawed); diff --git a/src/compile/compile.c b/src/compile/compile.c index 490bc43..5432bc1 100644 --- a/src/compile/compile.c +++ b/src/compile/compile.c @@ -19,6 +19,27 @@ struct reloc_helper { #define VEC_NAME addrs #include "../vec.h" +/* skip assertions since we know they must be valid due to type checking earlier */ +static long checked_run_i(struct ejit_func *f, size_t argc, struct ejit_arg args[argc]) +{ + return ejit_run(f, argc, args, NULL).i; +} + +static int64_t checked_run_l(struct ejit_func *f, size_t argc, struct ejit_arg args[argc]) +{ + return ejit_run(f, argc, args, NULL).i; +} + +static float checked_run_f(struct ejit_func *f, size_t argc, struct ejit_arg args[argc]) +{ + return ejit_run(f, argc, args, NULL).f; +} + +static double checked_run_d(struct ejit_func *f, size_t argc, struct ejit_arg args[argc]) +{ + return ejit_run(f, argc, args, NULL).f; +} + static void *alloc_arena(size_t size, bool im_scawed) { return mmap(NULL, size, @@ -26,6 +47,24 @@ static void *alloc_arena(size_t size, bool im_scawed) MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } +static void assert_helper(const char *msg) +{ + assert(false && msg); +} + +static bool gpr_free(size_t argc, jit_operand_t args[argc], jit_gpr_t r) +{ + for (size_t i = 0; i < argc; ++i) { + if (args[i].kind != JIT_OPERAND_KIND_GPR) + continue; + + if (jit_gpr_regno(args[i].loc.gpr.gpr) == jit_gpr_regno(r)) + return false; + } + + return true; +} + static void free_arena(void *arena, size_t size) { munmap(arena, size); @@ -545,7 +584,7 @@ static void compile_absr_d(struct ejit_func *f, jit_state_t *j, { jit_fpr_t r0 = getfpr(f, i.r0, 0); jit_fpr_t r1 = getloc_d(f, j, i.r1, 1); - jit_absr_f(j, r0, r1); + jit_absr_d(j, r0, r1); putloc_d(f, j, i.r0, r0); } @@ -1305,6 +1344,23 @@ static void compile_truncr_f_32(struct ejit_func *f, jit_state_t *j, #endif } +static void compile_sqrtr_f(struct ejit_func *f, jit_state_t *j, + struct ejit_insn i) +{ + jit_fpr_t r0 = getfpr(f, i.r0, 0); + jit_fpr_t r1 = getloc_f(f, j, i.r1, 1); + jit_sqrtr_f(j, r0, r1); + putloc_d(f, j, i.r0, r0); +} + +static void compile_sqrtr_d(struct ejit_func *f, jit_state_t *j, + struct ejit_insn i) +{ + jit_fpr_t r0 = getfpr(f, i.r0, 0); + jit_fpr_t r1 = getloc_d(f, j, i.r1, 1); + jit_sqrtr_d(j, r0, r1); + putloc_d(f, j, i.r0, r0); +} static void compile_reg_cmp(struct ejit_func *f, jit_state_t *j, struct ejit_insn i, @@ -1783,7 +1839,7 @@ static enum jit_operand_abi jit_abi_from(enum ejit_type t) case EJIT_POINTER: return JIT_OPERAND_ABI_POINTER; case EJIT_FLOAT: return JIT_OPERAND_ABI_FLOAT; case EJIT_DOUBLE: return JIT_OPERAND_ABI_DOUBLE; - default: + default: break; } abort(); @@ -1803,7 +1859,7 @@ static size_t arg_offsetof(enum ejit_type t) 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); - default: + default: break; }; abort(); @@ -1869,19 +1925,19 @@ static void compile_trampoline(struct ejit_func *f, jit_state_t *j) foreach_vec(ii, f->insns) { struct ejit_insn i = *insns_at(&f->insns, ii); switch (i.op) { - case PARAM: { + case EJIT_OP_PARAM: { jit_operand_t p = jit_operand_mem(jit_abi_from(i.r1), JIT_R1, arg_offset(i)); operands_append(&args, p); break; } - case PARAM_F: { + case EJIT_OP_PARAM_F: { jit_operand_t p = jit_operand_mem(jit_abi_from(i.r1), JIT_R1, arg_offset(i)); operands_append(&args, p); break; } - case START: { + case EJIT_OP_START: { /* callr should be smart enough to avoid JIT_R0 if some * other register wants to write to it */ jit_reloc_t r = jit_mov_addr(j, JIT_R0); @@ -1889,7 +1945,7 @@ static void compile_trampoline(struct ejit_func *f, jit_state_t *j) jit_leave_jit_abi(j, 0, 0, frame); jit_ret(j); /* should just forward the return value */ - f->direct_call = jit_address(j); + f->direct_call = jit_address_to_function_pointer(jit_address(j)); jit_patch_here(j, r); operands_destroy(&args); @@ -1901,6 +1957,84 @@ static void compile_trampoline(struct ejit_func *f, jit_state_t *j) } } +static void resolve_top_reloc(jit_state_t *j, struct relocs *relocs, struct addrs *addrs, size_t ii) +{ + assert(relocs_len(relocs) != 0); + + struct reloc_helper h = *relocs_back(relocs); + if (h.to >= ii) + return; + + jit_addr_t a = *addrs_at(addrs, h.to); + jit_reloc_t r = h.r; + + assert(a); + jit_patch_there(j, r, a); + relocs_pop(relocs); +} + +static void resolve_relocs(jit_state_t *j, struct relocs *relocs, struct addrs *addrs, size_t ii) +{ + foreach_vec(ri, *relocs) { + struct reloc_helper h = *relocs_at(relocs, ri); + if (h.to != ii) + continue; + + jit_addr_t a = *addrs_at(addrs, ii); + jit_reloc_t r = h.r; + + assert(a); + jit_patch_there(j, r, a); + + /* 'shift' down */ + if (ri != relocs_len(relocs) - 1) + *relocs_at(relocs, ri) = *relocs_back(relocs); + + assert(relocs_len(relocs) != 0); + relocs_shrink(relocs, relocs_len(relocs) - 1); + } +} + +static void compile_maxr_f(struct ejit_func *f, jit_state_t *j, + struct ejit_insn i) +{ + jit_fpr_t r0 = getfpr(f, i.r0, 0); + jit_fpr_t r1 = getloc_f(f, j, i.r1, 1); + jit_fpr_t r2 = getloc_f(f, j, i.r2, 2); + jit_maxr_f(j, r0, r1, r2); + putloc_f(f, j, i.r0, r0); +} + +static void compile_maxr_d(struct ejit_func *f, jit_state_t *j, + struct ejit_insn i) +{ + jit_fpr_t r0 = getfpr(f, i.r0, 0); + jit_fpr_t r1 = getloc_d(f, j, i.r1, 1); + jit_fpr_t r2 = getloc_d(f, j, i.r2, 2); + jit_maxr_d(j, r0, r1, r2); + putloc_d(f, j, i.r0, r0); +} + +static void compile_minr_f(struct ejit_func *f, jit_state_t *j, + struct ejit_insn i) +{ + jit_fpr_t r0 = getfpr(f, i.r0, 0); + jit_fpr_t r1 = getloc_f(f, j, i.r1, 1); + jit_fpr_t r2 = getloc_f(f, j, i.r2, 2); + jit_minr_f(j, r0, r1, r2); + putloc_f(f, j, i.r0, r0); +} + +static void compile_minr_d(struct ejit_func *f, jit_state_t *j, + struct ejit_insn i) +{ + jit_fpr_t r0 = getfpr(f, i.r0, 0); + jit_fpr_t r1 = getloc_d(f, j, i.r1, 1); + jit_fpr_t r2 = getloc_d(f, j, i.r2, 2); + jit_minr_d(j, r0, r1, r2); + putloc_d(f, j, i.r0, r0); +} + static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, size_t size) { @@ -1922,204 +2056,373 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, struct operands dst = operands_create(); struct operands direct = operands_create(); - struct relocs relocs = relocs_create(sizeof(struct reloc_helper)); + struct relocs relocs = relocs_create(); struct addrs addrs = addrs_create(); addrs_reserve(&addrs, insns_len(&f->insns)); - void *call = NULL; - size_t label = 0; foreach_vec(ii, f->insns) { /* if we've hit a label, add it to our vector of label addresses */ if (label < labels_len(&f->labels)) { if (*labels_at(&f->labels, label) == ii) { compile_label(j, ii, &addrs); + resolve_relocs(j, &relocs, &addrs, ii); label++; } } struct ejit_insn i = *insns_at(&f->insns, ii); switch (i.op) { - case MOVR: compile_movr(f, j, i); break; - case MOVR_F: compile_movr_f(f, j, i); break; - case MOVR_D: compile_movr_d(f, j, i); break; - - case MOVI: compile_movi(f, j, i); break; - case MOVI_F: compile_movi_f(f, j, i); break; - case MOVI_D: compile_movi_d(f, j, i); break; - - case ADDR: compile_addr(f, j, i); break; - case ADDI: compile_addi(f, j, i); break; - case ADDR_F: compile_addr_f(f, j, i); break; - case ADDR_D: compile_addr_d(f, j, i); break; - - case SUBR: compile_subr(f, j, i); break; - case SUBI: compile_subi(f, j, i); break; - case SUBR_F: compile_subr_f(f, j, i); break; - case SUBR_D: compile_subr_d(f, j, i); break; - - case MULR: compile_mulr(f, j, i); break; - case MULR_F: compile_mulr_f(f, j, i); break; - case MULR_D: compile_mulr_d(f, j, i); break; - - case ANDI: compile_andi(f, j, i); break; - case ANDR: compile_andr(f, j, i); break; - - case ORI: compile_ori(f, j, i); break; - case ORR: compile_orr(f, j, i); break; - - case XORI: compile_xori(f, j, i); break; - case XORR: compile_xorr(f, j, i); break; - - case DIVR: compile_divr(f, j, i); break; - case DIVR_U: compile_divr_u(f, j, i); break; - case DIVR_F: compile_divr_f(f, j, i); break; - case DIVR_D: compile_divr_d(f, j, i); break; - - case REMR: compile_remr(f, j, i); break; - case REMR_U: compile_remr_u(f, j, i); break; - - case ABSR_F: compile_absr_f(f, j, i); break; - case ABSR_D: compile_absr_d(f, j, i); break; - - case LSHI: compile_lshi(f, j, i); break; - case LSHR: compile_lshr(f, j, i); break; - case RSHI: compile_rshi(f, j, i); break; - case RSHI_U: compile_rshi_u(f, j, i); break; - case RSHR: compile_rshr(f, j, i); break; - case RSHR_U: compile_rshr_u(f, j, i); break; - - case STI8: compile_sti8(f, j, i); break; - case STI16: compile_sti16(f, j, i); break; - case STI32: compile_sti32(f, j, i); break; - case STI64: compile_sti64(f, j, i); break; - case STIF: compile_stif(f, j, i); break; - case STID: compile_stid(f, j, i); break; - - case STXI8: compile_stxi8(f, j, i); break; - case STXI16: compile_stxi16(f, j, i); break; - case STXI32: compile_stxi32(f, j, i); break; - case STXI64: compile_stxi64(f, j, i); break; - case STXIF: compile_stxif(f, j, i); break; - case STXID: compile_stxid(f, j, i); break; - - case STXR8: compile_stxr8(f, j, i); break; - case STXR16: compile_stxr16(f, j, i); break; - case STXR32: compile_stxr32(f, j, i); break; - case STXR64: compile_stxr64(f, j, i); break; - case STXRF: compile_stxrf(f, j, i); break; - case STXRD: compile_stxrd(f, j, i); break; - - case LDI8: compile_ldi8(f, j, i); break; - case LDI16: compile_ldi16(f, j, i); break; - case LDI32: compile_ldi32(f, j, i); break; - case LDI64: compile_ldi64(f, j, i); break; - case LDIU8: compile_ldiu8(f, j, i); break; - case LDIU16: compile_ldiu16(f, j, i); break; - case LDIU32: compile_ldiu32(f, j, i); break; - case LDIU64: compile_ldiu64(f, j, i); break; - case LDIF: compile_ldif(f, j, i); break; - case LDID: compile_ldid(f, j, i); break; - - case LDXI8: compile_ldxi8(f, j, i); break; - case LDXI16: compile_ldxi16(f, j, i); break; - case LDXI32: compile_ldxi32(f, j, i); break; - case LDXI64: compile_ldxi64(f, j, i); break; - case LDXIU8: compile_ldxiu8(f, j, i); break; - case LDXIU16: compile_ldxiu16(f, j, i); break; - case LDXIU32: compile_ldxiu32(f, j, i); break; - case LDXIU64: compile_ldxiu64(f, j, i); break; - case LDXIF: compile_ldxif(f, j, i); break; - case LDXID: compile_ldxid(f, j, i); break; - - case LDXR8: compile_ldxr8(f, j, i); break; - case LDXR16: compile_ldxr16(f, j, i); break; - case LDXR32: compile_ldxr32(f, j, i); break; - case LDXR64: compile_ldxr64(f, j, i); break; - case LDXRU8: compile_ldxru8(f, j, i); break; - case LDXRU16: compile_ldxru16(f, j, i); break; - case LDXRU32: compile_ldxru32(f, j, i); break; - case LDXRU64: compile_ldxru64(f, j, i); break; - case LDXRF: compile_ldxrf(f, j, i); break; - case LDXRD: compile_ldxrd(f, j, i); break; - - case COMR: compile_comr(f, j, i); break; - - case NEGR: compile_negr(f, j, i); break; - case NEGR_F: compile_negr_f(f, j, i); break; - case NEGR_D: compile_negr_d(f, j, i); break; - - case EXTR8: compile_extr8(f, j, i); break; - case EXTR16: compile_extr16(f, j, i); break; - case EXTR32: compile_extr32(f, j, i); break; - case EXTRU8: compile_extru8(f, j, i); break; - case EXTRU16: compile_extru16(f, j, i); break; - case EXTRU32: compile_extru32(f, j, i); break; - case EXTRF: compile_extrf(f, j, i); break; - case EXTRD: compile_extrd(f, j, i); break; - - case TRUNCR_D_32: compile_truncr_d_32(f, j, i); break; - case TRUNCR_D_64: compile_truncr_d_64(f, j, i); break; - case TRUNCR_F_32: compile_truncr_f_32(f, j, i); break; - case TRUNCR_F_64: compile_truncr_f_64(f, j, i); break; - - case EQR: compile_eqr(f, j, i); break; - case EQR_F: compile_eqr_f(f, j, i); break; - case EQR_D: compile_eqr_d(f, j, i); break; - - case NER: compile_ner(f, j, i); break; - case NER_F: compile_ner_f(f, j, i); break; - case NER_D: compile_ner_d(f, j, i); break; - - case GER: compile_ger(f, j, i); break; - case GER_U: compile_ger_u(f, j, i); break; - case GER_F: compile_ger_f(f, j, i); break; - case GER_D: compile_ger_d(f, j, i); break; - - case GTR: compile_gtr(f, j, i); break; - case GTR_U: compile_gtr_u(f, j, i); break; - case GTR_F: compile_gtr_f(f, j, i); break; - case GTR_D: compile_gtr_d(f, j, i); break; - - case BMCI: compile_bmci(f, j, i, &relocs); break; - case BMCR: compile_bmcr(f, j, i, &relocs); break; - - case BMSI: compile_bmsi(f, j, i, &relocs); break; - case BMSR: compile_bmsr(f, j, i, &relocs); break; - - case BEQR: compile_beqr(f, j, i, &relocs); break; - case BEQI: compile_beqi(f, j, i, &relocs); break; - case BEQR_F: compile_beqr_f(f, j, i, &relocs); break; - case BEQR_D: compile_beqr_d(f, j, i, &relocs); break; - - case BNER: compile_bner(f, j, i, &relocs); break; - case BNEI: compile_bnei(f, j, i, &relocs); break; - case BNER_F: compile_bner_f(f, j, i, &relocs); break; - case BNER_D: compile_bner_d(f, j, i, &relocs); break; - - case BGER: compile_bger(f, j, i, &relocs); break; - case BGER_U: compile_bger_u(f, j, i, &relocs); break; - case BGEI: compile_bgei(f, j, i, &relocs); break; - case BGEI_U: compile_bgei_u(f, j, i, &relocs); break; - case BGER_F: compile_bger_f(f, j, i, &relocs); break; - case BGER_D: compile_bger_d(f, j, i, &relocs); break; - - case BGTR: compile_bgtr(f, j, i, &relocs); break; - case BGTR_U: compile_bgtr_u(f, j, i, &relocs); break; - case BGTI: compile_bgti(f, j, i, &relocs); break; - case BGTI_U: compile_bgti_u(f, j, i, &relocs); break; - case BGTR_F: compile_bgtr_f(f, j, i, &relocs); break; - case BGTR_D: compile_bgtr_d(f, j, i, &relocs); break; - - case BLEI: compile_blei(f, j, i, &relocs); break; - case BLEI_U: compile_blei_u(f, j, i, &relocs); break; - - case BLTI: compile_blti(f, j, i, &relocs); break; - case BLTI_U: compile_blti_u(f, j, i, &relocs); break; - - case JMP: compile_jmp(f, j, i, &relocs); break; - - case ARG: { + case EJIT_OP_MOVR: compile_movr(f, j, i); break; + case EJIT_OP_MOVR_F: compile_movr_f(f, j, i); break; + case EJIT_OP_MOVR_D: compile_movr_d(f, j, i); break; + + case EJIT_OP_MOVI: compile_movi(f, j, i); break; + case EJIT_OP_MOVI_F: compile_movi_f(f, j, i); break; + case EJIT_OP_MOVI_D: compile_movi_d(f, j, i); break; + + case EJIT_OP_ADDR: compile_addr(f, j, i); break; + case EJIT_OP_ADDI: compile_addi(f, j, i); break; + case EJIT_OP_ADDR_F: compile_addr_f(f, j, i); break; + case EJIT_OP_ADDR_D: compile_addr_d(f, j, i); break; + + case EJIT_OP_SUBR: compile_subr(f, j, i); break; + case EJIT_OP_SUBI: compile_subi(f, j, i); break; + case EJIT_OP_SUBR_F: compile_subr_f(f, j, i); break; + case EJIT_OP_SUBR_D: compile_subr_d(f, j, i); break; + + case EJIT_OP_MULR: compile_mulr(f, j, i); break; + case EJIT_OP_MULR_F: compile_mulr_f(f, j, i); break; + case EJIT_OP_MULR_D: compile_mulr_d(f, j, i); break; + + case EJIT_OP_ANDI: compile_andi(f, j, i); break; + case EJIT_OP_ANDR: compile_andr(f, j, i); break; + + case EJIT_OP_ORI: compile_ori(f, j, i); break; + case EJIT_OP_ORR: compile_orr(f, j, i); break; + + case EJIT_OP_XORI: compile_xori(f, j, i); break; + case EJIT_OP_XORR: compile_xorr(f, j, i); break; + + case EJIT_OP_DIVR: compile_divr(f, j, i); break; + case EJIT_OP_DIVR_U: compile_divr_u(f, j, i); break; + case EJIT_OP_DIVR_F: compile_divr_f(f, j, i); break; + case EJIT_OP_DIVR_D: compile_divr_d(f, j, i); break; + + case EJIT_OP_REMR: compile_remr(f, j, i); break; + case EJIT_OP_REMR_U: compile_remr_u(f, j, i); break; + + case EJIT_OP_ABSR_F: compile_absr_f(f, j, i); break; + case EJIT_OP_ABSR_D: compile_absr_d(f, j, i); break; + + case EJIT_OP_LSHI: compile_lshi(f, j, i); break; + case EJIT_OP_LSHR: compile_lshr(f, j, i); break; + case EJIT_OP_RSHI: compile_rshi(f, j, i); break; + case EJIT_OP_RSHI_U: compile_rshi_u(f, j, i); break; + case EJIT_OP_RSHR: compile_rshr(f, j, i); break; + case EJIT_OP_RSHR_U: compile_rshr_u(f, j, i); break; + + case EJIT_OP_STI8: compile_sti8(f, j, i); break; + case EJIT_OP_STI16: compile_sti16(f, j, i); break; + case EJIT_OP_STI32: compile_sti32(f, j, i); break; + case EJIT_OP_STI64: compile_sti64(f, j, i); break; + case EJIT_OP_STIF: compile_stif(f, j, i); break; + case EJIT_OP_STID: compile_stid(f, j, i); break; + + case EJIT_OP_STXI8: compile_stxi8(f, j, i); break; + case EJIT_OP_STXI16: compile_stxi16(f, j, i); break; + case EJIT_OP_STXI32: compile_stxi32(f, j, i); break; + case EJIT_OP_STXI64: compile_stxi64(f, j, i); break; + case EJIT_OP_STXIF: compile_stxif(f, j, i); break; + case EJIT_OP_STXID: compile_stxid(f, j, i); break; + + case EJIT_OP_STXR8: compile_stxr8(f, j, i); break; + case EJIT_OP_STXR16: compile_stxr16(f, j, i); break; + case EJIT_OP_STXR32: compile_stxr32(f, j, i); break; + case EJIT_OP_STXR64: compile_stxr64(f, j, i); break; + case EJIT_OP_STXRF: compile_stxrf(f, j, i); break; + case EJIT_OP_STXRD: compile_stxrd(f, j, i); break; + + case EJIT_OP_LDI8: compile_ldi8(f, j, i); break; + case EJIT_OP_LDI16: compile_ldi16(f, j, i); break; + case EJIT_OP_LDI32: compile_ldi32(f, j, i); break; + case EJIT_OP_LDI64: compile_ldi64(f, j, i); break; + case EJIT_OP_LDIU8: compile_ldiu8(f, j, i); break; + case EJIT_OP_LDIU16: compile_ldiu16(f, j, i); break; + case EJIT_OP_LDIU32: compile_ldiu32(f, j, i); break; + case EJIT_OP_LDIU64: compile_ldiu64(f, j, i); break; + case EJIT_OP_LDIF: compile_ldif(f, j, i); break; + case EJIT_OP_LDID: compile_ldid(f, j, i); break; + + case EJIT_OP_LDXI8: compile_ldxi8(f, j, i); break; + case EJIT_OP_LDXI16: compile_ldxi16(f, j, i); break; + case EJIT_OP_LDXI32: compile_ldxi32(f, j, i); break; + case EJIT_OP_LDXI64: compile_ldxi64(f, j, i); break; + case EJIT_OP_LDXIU8: compile_ldxiu8(f, j, i); break; + case EJIT_OP_LDXIU16: compile_ldxiu16(f, j, i); break; + case EJIT_OP_LDXIU32: compile_ldxiu32(f, j, i); break; + case EJIT_OP_LDXIU64: compile_ldxiu64(f, j, i); break; + case EJIT_OP_LDXIF: compile_ldxif(f, j, i); break; + case EJIT_OP_LDXID: compile_ldxid(f, j, i); break; + + case EJIT_OP_LDXR8: compile_ldxr8(f, j, i); break; + case EJIT_OP_LDXR16: compile_ldxr16(f, j, i); break; + case EJIT_OP_LDXR32: compile_ldxr32(f, j, i); break; + case EJIT_OP_LDXR64: compile_ldxr64(f, j, i); break; + case EJIT_OP_LDXRU8: compile_ldxru8(f, j, i); break; + case EJIT_OP_LDXRU16: compile_ldxru16(f, j, i); break; + case EJIT_OP_LDXRU32: compile_ldxru32(f, j, i); break; + case EJIT_OP_LDXRU64: compile_ldxru64(f, j, i); break; + case EJIT_OP_LDXRF: compile_ldxrf(f, j, i); break; + case EJIT_OP_LDXRD: compile_ldxrd(f, j, i); break; + + case EJIT_OP_COMR: compile_comr(f, j, i); break; + + case EJIT_OP_NEGR: compile_negr(f, j, i); break; + case EJIT_OP_NEGR_F: compile_negr_f(f, j, i); break; + case EJIT_OP_NEGR_D: compile_negr_d(f, j, i); break; + + case EJIT_OP_EXTR8: compile_extr8(f, j, i); break; + case EJIT_OP_EXTR16: compile_extr16(f, j, i); break; + case EJIT_OP_EXTR32: compile_extr32(f, j, i); break; + case EJIT_OP_EXTRU8: compile_extru8(f, j, i); break; + case EJIT_OP_EXTRU16: compile_extru16(f, j, i); break; + case EJIT_OP_EXTRU32: compile_extru32(f, j, i); break; + case EJIT_OP_EXTRF: compile_extrf(f, j, i); break; + case EJIT_OP_EXTRD: compile_extrd(f, j, i); break; + + case EJIT_OP_TRUNCR_D_32: compile_truncr_d_32(f, j, i); break; + case EJIT_OP_TRUNCR_D_64: compile_truncr_d_64(f, j, i); break; + case EJIT_OP_TRUNCR_F_32: compile_truncr_f_32(f, j, i); break; + case EJIT_OP_TRUNCR_F_64: compile_truncr_f_64(f, j, i); break; + + case EJIT_OP_SQRTR_F: compile_sqrtr_f(f, j, i); break; + case EJIT_OP_SQRTR_D: compile_sqrtr_d(f, j, i); break; + + case EJIT_OP_MINR_F: compile_minr_f(f, j, i); break; + case EJIT_OP_MINR_D: compile_minr_d(f, j, i); break; + + case EJIT_OP_MAXR_F: compile_maxr_f(f, j, i); break; + case EJIT_OP_MAXR_D: compile_maxr_d(f, j, i); break; + + case EJIT_OP_EQR: compile_eqr(f, j, i); break; + case EJIT_OP_EQR_F: compile_eqr_f(f, j, i); break; + case EJIT_OP_EQR_D: compile_eqr_d(f, j, i); break; + + case EJIT_OP_NER: compile_ner(f, j, i); break; + case EJIT_OP_NER_F: compile_ner_f(f, j, i); break; + case EJIT_OP_NER_D: compile_ner_d(f, j, i); break; + + case EJIT_OP_GER: compile_ger(f, j, i); break; + case EJIT_OP_GER_U: compile_ger_u(f, j, i); break; + case EJIT_OP_GER_F: compile_ger_f(f, j, i); break; + case EJIT_OP_GER_D: compile_ger_d(f, j, i); break; + + case EJIT_OP_GTR: compile_gtr(f, j, i); break; + case EJIT_OP_GTR_U: compile_gtr_u(f, j, i); break; + case EJIT_OP_GTR_F: compile_gtr_f(f, j, i); break; + case EJIT_OP_GTR_D: compile_gtr_d(f, j, i); break; + + case EJIT_OP_BMCI: { + compile_bmci(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BMCR: { + compile_bmcr(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BMSI: { + compile_bmsi(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BMSR: { + compile_bmsr(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BEQR: { + compile_beqr(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BEQI: { + compile_beqi(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BEQR_F: { + compile_beqr_f(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BEQR_D: { + compile_beqr_d(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BNER: { + compile_bner(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BNEI: { + compile_bnei(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BNER_F: { + compile_bner_f(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BNER_D: { + compile_bner_d(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGER: { + compile_bger(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGER_U: { + compile_bger_u(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGEI: { + compile_bgei(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGEI_U: { + compile_bgei_u(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGER_F: { + compile_bger_f(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGER_D: { + compile_bger_d(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGTR: { + compile_bgtr(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGTR_U: { + compile_bgtr_u(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGTI: { + compile_bgti(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGTI_U: { + compile_bgti_u(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGTR_F: { + compile_bgtr_f(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BGTR_D: { + compile_bgtr_d(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BLEI: { + compile_blei(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BLEI_U: { + compile_blei_u(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BLTI: { + compile_blti(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_BLTI_U: { + compile_blti_u(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_JMP: { + compile_jmp(f, j, i, &relocs); + resolve_top_reloc(j, &relocs, &addrs, ii); + break; + } + + case EJIT_OP_ARG_I: { + jit_operand_t type = jit_operand_imm(JIT_OPERAND_ABI_WORD, i.r1); + jit_operand_t arg = jit_operand_imm(jit_abi_from(i.r1), i.o); + operands_append(&src, type); + operands_append(&src, arg); + operands_append(&direct, 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)) + }; + + operands_append(&dst, to[0]); + operands_append(&dst, to[1]); + break; + } + + case EJIT_OP_ARG_FI: { + assert(false && "immediate floats (currently?) not supported"); + abort(); + break; + } + + case EJIT_OP_ARG: { size_t r2 = gpr_stats_at(&f->gpr, i.r2)->rno; jit_operand_t type = jit_operand_imm(JIT_OPERAND_ABI_WORD, i.r1); @@ -2152,12 +2455,12 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, break; } - case ARG_F: { + case EJIT_OP_ARG_F: { size_t f2 = fpr_stats_at(&f->fpr, i.r2)->fno; jit_operand_t type = jit_operand_imm(JIT_OPERAND_ABI_WORD, i.r1); jit_operand_t arg; - if (i.r2 < physfpr_count()) { + if (f2 < physfpr_count()) { /* regular register */ arg = jit_operand_fpr(jit_abi_from(i.r1), physfpr_at(f2)); @@ -2186,17 +2489,10 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, break; } - case ESCAPEI_L: -#if __WORDSIZE == 64 - /* fallthrough */ -#else - assert(0 && "trying to compile escapei_l on 32bit arch"); - break; -#endif - - case ESCAPEI_D: - case ESCAPEI_F: - case ESCAPEI_I: { + case EJIT_OP_ESCAPEI_I: + case EJIT_OP_ESCAPEI_L: + case EJIT_OP_ESCAPEI_F: + case EJIT_OP_ESCAPEI_D: { save_caller_save_regs(f, j); jit_operand_t args[2] = { @@ -2206,7 +2502,7 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, * argument stack address */ jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R0) }; - compile_imm_call(j, &src, &dst, (void *)(uintptr_t)i.o, 2, args); + compile_imm_call(j, &src, &dst, (void *)i.p, 2, args); restore_caller_save_regs(f, j); operands_reset(&src); @@ -2215,21 +2511,165 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, break; } - case CALLI_L: -#if __WORDSIZE == 64 - call = ejit_run_func_l; goto calli; -#else - assert(0 && "trying to compile calli_l on 32bit arch"); - break; + case EJIT_OP_TAILI: { + /* a bit of copy-paste between this and the next func, + * hmm */ + assert(operands_len(&direct) <= 2); + struct ejit_func *f = (struct ejit_func *)i.p; + assert(f->direct_call); + + jit_operand_t regs[2] = { + jit_operand_gpr(JIT_OPERAND_ABI_WORD, JIT_R1), + jit_operand_gpr(JIT_OPERAND_ABI_WORD, JIT_R2) + }; + jit_move_operands(j, regs, direct.buf, operands_len(&direct)); + + int frame_size = j->frame_size; + jit_shrink_stack(j, stack); + jit_leave_jit_abi(j, gprs, fprs, frame); + + /* now move args into place */ + jit_operand_t args[2] = {}; + foreach_vec(oi, direct) { + args[oi] = *operands_at(&direct, oi); + } + + jit_locate_args(j, operands_len(&direct), args); + jit_move_operands(j, args, regs, operands_len(&direct)); + jit_jmpi(j, f->direct_call); + j->frame_size = frame_size; + + operands_reset(&src); + operands_reset(&dst); + operands_reset(&direct); + break; + } + + case EJIT_OP_TAILR: { + /* this is admittedly a slightly roundabout way of + * implementing tail calls and is arguably not the most + * performant way (if it works at all, heh) but for now + * I'm more interested in functionality than raw + * performance. Currently only supports two gpr + * registers, but should be fairly easy to extend with + * fprs as well */ + + assert(operands_len(&direct) <= 2); + jit_gpr_t r = getloc(f, j, i.r1, 0); + +#if defined(DEBUG) + jit_ldxi(j, JIT_R1, r, offsetof(struct ejit_func, rtype)); + jit_reloc_t rtype_reloc = jit_beqi(j, JIT_R1, f->rtype); + jit_calli_1(j, assert_helper, + jit_operand_imm(JIT_OPERAND_ABI_POINTER, + (jit_imm_t)"trying to tail call different rtype")); + + jit_patch_here(j, rtype_reloc); + + jit_ldxi(j, JIT_R1, r, offsetof(struct ejit_func, direct_call)); + jit_reloc_t direct_reloc = jit_bnei(j, JIT_R1, 0); /* null */ + jit_calli_1(j, assert_helper, + jit_operand_imm(JIT_OPERAND_ABI_POINTER, + (jit_imm_t)"trying to tail call interpreted function")); + jit_patch_here(j, direct_reloc); #endif + size_t argc = operands_len(&direct); + + /* r0 = target, r1 = arg1, r2 = arg2 */ + jit_ldxi(j, JIT_R0, r, offsetof(struct ejit_func, direct_call)); + jit_operand_t regs[3] = { + jit_operand_gpr(JIT_OPERAND_ABI_WORD, JIT_R1), + jit_operand_gpr(JIT_OPERAND_ABI_WORD, JIT_R2) + }; + jit_move_operands(j, regs, direct.buf, argc); + + /* with args safely in registers, reset stack/state + * while avoiding overwriting the call target */ + int frame_size = j->frame_size; + jit_shrink_stack(j, stack); + jit_leave_jit_abi(j, gprs, fprs, frame); + + /* now move args into place, making sure we avoid our + * target register */ + jit_operand_t args[3] = {}; + for (size_t oi = 0; oi < argc; ++oi) { + args[oi] = *operands_at(&direct, oi); + } + + jit_locate_args(j, argc, args); + + /* we know that at least one gpr must be free */ + jit_gpr_t target = gpr_free(argc, args, JIT_R0) ? JIT_R0 + : gpr_free(argc, args, JIT_R1) ? JIT_R1 + : gpr_free(argc, args, JIT_R2) ? JIT_R2 + : (abort(), JIT_R0); + + /* move our target in JIT_R0 to whatever the free + * register is to avoid it being clobbered when we move + * the actual arguments */ + args[argc] = jit_operand_gpr(JIT_OPERAND_ABI_POINTER, target); + regs[argc] = jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R0); + jit_move_operands(j, args, regs, argc + 1); + jit_jmpr(j, target); + j->frame_size = frame_size; + + operands_reset(&src); + operands_reset(&dst); + operands_reset(&direct); + break; + } + + case EJIT_OP_CALLR_I: + case EJIT_OP_CALLR_L: + case EJIT_OP_CALLR_F: + case EJIT_OP_CALLR_D: { + save_caller_save_regs(f, j); + + jit_gpr_t target = getgpr(f, i.r1, 0); + + /* check if there's a direct call avaiable */ + jit_ldxi(j, JIT_R1, target, offsetof(struct ejit_func, direct_call)); + jit_reloc_t direct_reloc = jit_beqi(j, JIT_R0, 0); + /* we can do a jit -> jit call */ + jit_callr(j, JIT_R1, operands_len(&direct), direct.buf); + jit_reloc_t out_reloc = jit_jmp(j); + + jit_patch_here(j, direct_reloc); - case CALLI_F: { call = ejit_run_func_f; goto calli; } - case CALLI_D: { call = ejit_run_func_d; goto calli; } - case CALLI_I: { call = ejit_run_func_i; goto calli; -calli: + /* we must do a jit -> bytecode call */ + jit_operand_t args[3] = { + jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R1), + jit_operand_imm(JIT_OPERAND_ABI_WORD, operands_len(&src) / 2), + /* compile_imm_call populate JIT_R0 with the + * argument stack address */ + jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R0) + }; + void *call = NULL; + switch (i.op) { + case EJIT_OP_CALLR_I: call = ejit_run_func_i; break; + case EJIT_OP_CALLR_L: call = ejit_run_func_l; break; + case EJIT_OP_CALLR_F: call = ejit_run_func_f; break; + case EJIT_OP_CALLR_D: call = ejit_run_func_d; break; + default: abort(); + } + + compile_imm_call(j, &src, &dst, call, 3, args); + jit_patch_here(j, out_reloc); + restore_caller_save_regs(f, j); + + operands_reset(&src); + operands_reset(&dst); + operands_reset(&direct); + break; + } + + case EJIT_OP_CALLI: { save_caller_save_regs(f, j); - struct ejit_func *f = (struct ejit_func *)(uintptr_t)i.o; + struct ejit_func *f = (struct ejit_func *)i.p; +#if __WORDSIZE != 64 + assert(f->rtype != EJIT_INT64 && f->rtype != EJIT_UINT64); +#endif if (f && f->direct_call) { jit_calli(j, f->direct_call, operands_len(&direct), direct.buf); restore_caller_save_regs(f, j); @@ -2248,6 +2688,16 @@ calli: * argument stack address */ jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R0) }; + + void *call = NULL; + switch (f->rtype) { + case EJIT_INT64: + case EJIT_UINT64: call = checked_run_l; break; + case EJIT_FLOAT: call = checked_run_f; break; + case EJIT_DOUBLE: call = checked_run_d; break; + default: call = checked_run_i; break; + } + compile_imm_call(j, &src, &dst, call, 3, args); restore_caller_save_regs(f, j); @@ -2257,54 +2707,70 @@ calli: break; } - case RETVAL: compile_retval(f, j, i); break; - case RETVAL_F: compile_retval_f(f, j, i); break; - case RETVAL_D: compile_retval_d(f, j, i); break; + case EJIT_OP_RETVAL: compile_retval(f, j, i); break; + case EJIT_OP_RETVAL_F: compile_retval_f(f, j, i); break; + case EJIT_OP_RETVAL_D: compile_retval_d(f, j, i); break; - case RETR: { + case EJIT_OP_RETR: { jit_gpr_t r = getloc(f, j, i.r1, 0); /* R0 won't get overwritten by jit_leave_jit_abi */ jit_movr(j, JIT_R0, r); + + /* keep track of frame size so we can continue + * generating code after 'leaving' the ABI. Bit of a + * hack, should maybe codify this better in the + * lightening API? */ + int frame_size = j->frame_size; jit_shrink_stack(j, stack); jit_leave_jit_abi(j, gprs, fprs, frame); jit_retr(j, JIT_R0); + j->frame_size = frame_size; break; } - case RETR_F: { + case EJIT_OP_RETR_F: { jit_fpr_t r = getloc_f(f, j, i.r1, 0); jit_movr_f(j, JIT_F0, r); + + int frame_size = j->frame_size; jit_shrink_stack(j, stack); jit_leave_jit_abi(j, gprs, fprs, frame); jit_retr_f(j, JIT_F0); + j->frame_size = frame_size; break; } - case RETR_D: { + case EJIT_OP_RETR_D: { jit_fpr_t r = getloc_d(f, j, i.r1, 0); jit_movr_d(j, JIT_F0, r); + + int frame_size = j->frame_size; jit_shrink_stack(j, stack); jit_leave_jit_abi(j, gprs, fprs, frame); jit_retr_d(j, JIT_F0); + j->frame_size = frame_size; break; } - case RETI: { + case EJIT_OP_RETI: { + int frame_size = j->frame_size; jit_shrink_stack(j, stack); jit_leave_jit_abi(j, gprs, fprs, frame); jit_reti(j, i.o); + j->frame_size = frame_size; break; } - case END: { - /* 'void' return */ + case EJIT_OP_END: { + /* 'void' return, must be last thing in function so no + * need to keep track of frame size */ jit_shrink_stack(j, stack); jit_leave_jit_abi(j, gprs, fprs, frame); jit_reti(j, 0); break; } - case PARAM_F: { + case EJIT_OP_PARAM_F: { size_t f2 = fpr_stats_at(&f->fpr, i.r2)->fno; jit_operand_t to; @@ -2323,7 +2789,7 @@ calli: break; } - case PARAM: { + case EJIT_OP_PARAM: { size_t r2 = gpr_stats_at(&f->gpr, i.r2)->rno; jit_operand_t to; @@ -2342,7 +2808,7 @@ calli: break; } - case START: { + case EJIT_OP_START: { /* parameters should be done by now */ jit_load_args(j, operands_len(&dst), dst.buf); /* reuse for arguments */ @@ -2354,14 +2820,7 @@ calli: } } - foreach_vec(ri, relocs) { - struct reloc_helper h = *relocs_at(&relocs, ri); - jit_addr_t a = *addrs_at(&addrs, h.to); - jit_reloc_t r = h.r; - - assert(a); - jit_patch_there(j, r, a); - } + assert(relocs_len(&relocs) == 0); operands_destroy(&src); operands_destroy(&dst); @@ -2369,49 +2828,189 @@ calli: relocs_destroy(&relocs); addrs_destroy(&addrs); - if (jit_end(j, &size)) + if ((f->extern_call = jit_end(j, &size))) return 0; return size; } -/* highest prio first */ -static int gpr_sort_prio(struct gpr_stat *a, struct gpr_stat *b) +struct alive_slot { + long r; + size_t cost; + size_t idx; + size_t remap; +}; + +#define VEC_NAME alive +#define VEC_TYPE struct alive_slot +#include "../vec.h" + +static int spill_cost_sort(struct alive_slot *a, struct alive_slot *b) { - return (int)b->prio - (int)a->prio; + if (a->cost > b->cost) + return -1; + + return a->cost < b->cost; } -static int fpr_sort_prio(struct fpr_stat *a, struct fpr_stat *b) +/* slightly more parameters than I would like but I guess it's fine */ +static void calculate_alive(struct alive *alive, size_t idx, + size_t prio, size_t start, size_t end, size_t *rno, + void *regs, int (*dead)(void *regs, size_t idx, size_t start)) { - return (int)b->prio - (int)a->prio; + /* single-shot registers go in the special reserved slot */ + if (end <= start + 1) { + *rno = 0; + + struct alive_slot *a = alive_at(alive, 0); + a->cost += prio; + return; + } + + /* kill registers whose lifetime has ended */ + long max_cost_idx = -1; + size_t max_cost = 0; + long counter = 0; + foreach_vec(ai, *alive) { + /* skip oneshot */ + if (ai == 0) + goto next; + + struct alive_slot *a = alive_at(alive, ai); + if (a->r >= 0 && dead(regs, a->r, start)) + a->r = -1; /* gravestone */ + + if (a->r < 0 && a->cost > max_cost) { + max_cost = a->cost; + max_cost_idx = counter; + } + +next: + counter++; + } + + /* there's a suitable slot for us */ + if (max_cost_idx >= 0) { + *rno = max_cost_idx; + + struct alive_slot *a = alive_at(alive, max_cost_idx); + a->cost += prio; + a->r = idx; + return; + } + + *rno = alive_len(alive); + struct alive_slot a = { + .cost = prio, + .r = idx, + .idx = *rno + }; + alive_append(alive, a); } -/* sort registers by highest priority first, then renumber registers in the - * given order. Higher priority is given a physical register first. - * - * Note that the `->r` field becomes 'meaningless' after sorting, and you should - * only use the `->rno` field after this point. Essentially, if you have a - * register EJIT_GPR(2), you should use `gpr_stats_at(2)->rno` for the 'actual' - * register number in `getloc` and the like. - * - * Can be a bit confusing, but this way we don't have to allocate any new - * arrays, which is cool. */ +static int gpr_dead(void *regs, size_t idx, size_t start) +{ + struct gpr_stats *gprs = regs; + return gpr_stats_at(gprs, idx)->end <= start; +} + +static void linear_gpr_alloc(struct ejit_func *f) +{ + foreach_vec(gi, f->gpr) { + gpr_stats_at(&f->gpr, gi)->rno = gi; + } +} + +/* there's a fair bit of repetition between this and the gpr case, hmm */ static void assign_gprs(struct ejit_func *f) { - gpr_stats_sort(&f->gpr, (vec_comp_t)gpr_sort_prio); + /* everything fits into registers, no need to start optimizing */ + if (gpr_stats_len(&f->gpr) <= physgpr_count()) + return linear_gpr_alloc(f); + + struct alive alive = alive_create(gpr_stats_len(&f->gpr)); + + /* special oneshot register class */ + struct alive_slot a = {.r = -1, .cost = 0, .idx = 0}; + alive_append(&alive, a); + + foreach_vec(gi, f->gpr) { + struct gpr_stat *gpr = gpr_stats_at(&f->gpr, gi); + calculate_alive(&alive, gi, + gpr->prio, gpr->start, gpr->end, &gpr->rno, + &f->gpr, gpr_dead); + } + + /* sort so that the highest spill cost register classes are at the front and + * as such more likely to be placed in registers */ + alive_sort(&alive, (vec_comp_t)spill_cost_sort); + + /* update remapping info */ + for(size_t i = 0; i < alive_len(&alive); ++i) { + struct alive_slot *a = alive_at(&alive, i); + alive_at(&alive, a->idx)->remap = i; + } + + /* remap locations */ for (size_t i = 0; i < gpr_stats_len(&f->gpr); ++i) { - size_t rno = gpr_stats_at(&f->gpr, i)->r.r; - gpr_stats_at(&f->gpr, rno)->rno = i; + struct gpr_stat *gpr = gpr_stats_at(&f->gpr, i); + struct alive_slot *a = alive_at(&alive, gpr->rno); + gpr->rno = a->remap; + } + + alive_destroy(&alive); +} + +static int fpr_dead(void *regs, size_t idx, size_t start) +{ + struct fpr_stats *fprs = regs; + return fpr_stats_at(fprs, idx)->end <= start; +} + +static void linear_fpr_alloc(struct ejit_func *f) +{ + foreach_vec(fi, f->fpr) { + fpr_stats_at(&f->fpr, fi)->fno = fi; } } static void assign_fprs(struct ejit_func *f) { - fpr_stats_sort(&f->fpr, (vec_comp_t)fpr_sort_prio); + /* everything fits into registers, no need to start optimizing */ + if (fpr_stats_len(&f->fpr) <= physfpr_count()) + return linear_fpr_alloc(f); + + struct alive alive = alive_create(fpr_stats_len(&f->fpr)); + + /* special oneshot register class */ + struct alive_slot a = {.r = -1, .cost = 0, .idx = 0}; + alive_append(&alive, a); + + foreach_vec(fi, f->fpr) { + struct fpr_stat *fpr = fpr_stats_at(&f->fpr, fi); + calculate_alive(&alive, fi, + fpr->prio, fpr->start, fpr->end, &fpr->fno, + &f->fpr, fpr_dead); + } + + /* sort so that the highest spill cost register classes are at the front and + * as such more likely to be placed in registers */ + alive_sort(&alive, (vec_comp_t)spill_cost_sort); + + /* update remapping info */ + for(size_t i = 0; i < alive_len(&alive); ++i) { + struct alive_slot *a = alive_at(&alive, i); + alive_at(&alive, a->idx)->remap = i; + } + + /* remap locations */ for (size_t i = 0; i < fpr_stats_len(&f->fpr); ++i) { - size_t rno = fpr_stats_at(&f->fpr, i)->f.f; - fpr_stats_at(&f->fpr, rno)->fno = i; + struct fpr_stat *fpr = fpr_stats_at(&f->fpr, i); + struct alive_slot *a = alive_at(&alive, fpr->fno); + fpr->fno = a->remap; } + + alive_destroy(&alive); } static size_t align_up(size_t a, size_t n) @@ -2425,7 +3024,7 @@ static size_t align_up(size_t a, size_t n) bool ejit_compile(struct ejit_func *f, bool use_64, bool im_scawed) { (void)use_64; -#if __WORDSIZE == 32 +#if __WORDSIZE != 64 /* can't compile 64bit code on 32bit systems, give up early */ if (use_64) return false; @@ -1,4 +1,5 @@ #include <assert.h> +#include <stdio.h> #include <sys/mman.h> #include <ejit/ejit.h> @@ -47,9 +48,12 @@ static void update_gpr(struct ejit_func *f, struct ejit_gpr r0) struct gpr_stat *gpr = gpr_stats_at(&f->gpr, r0.r); /* presumably first time we see this gpr */ /** @todo are branches faster than a memory write? */ - if (gpr->prio == 0) + if (gpr->prio == 0) { + gpr->start = insns_len(&f->insns); gpr->r = r0; + } + gpr->end = insns_len(&f->insns); gpr->prio += f->prio; } @@ -59,9 +63,12 @@ static void update_fpr(struct ejit_func *f, struct ejit_fpr f0) fpr_stats_append(&f->fpr, zero_fpr_stat()); struct fpr_stat *fpr = fpr_stats_at(&f->fpr, f0.f); - if (fpr->prio == 0) + if (fpr->prio == 0) { + fpr->start = insns_len(&f->insns); fpr->f = f0; + } + fpr->end = insns_len(&f->insns); fpr->prio += f->prio; } @@ -161,6 +168,8 @@ static void emit_insn_af(struct ejit_func *f, enum ejit_opcode op, size_t idx, e static void emit_insn_ad(struct ejit_func *f, enum ejit_opcode op, size_t idx, enum ejit_type type, double d) { + fprintf(stderr, "warning: immediate floats are currently not supported.\n" + "Consider moving values into FPRs.\n"); struct ejit_insn i = {.op = op, .r0 = idx, .r1 = type, .d = d}; insns_append(&f->insns, i); } @@ -336,9 +345,11 @@ struct ejit_func *ejit_create_func(enum ejit_type rtype, size_t argc, f->fpr = fpr_stats_create(); f->arena = NULL; f->direct_call = NULL; + f->extern_call = NULL; f->size = 0; f->prio = 1; f->use_64 = false; + f->max_args = 0; for (size_t i = 0; i < argc; ++i) { types_append(&f->sign, args[i].type); @@ -346,20 +357,20 @@ struct ejit_func *ejit_create_func(enum ejit_type rtype, size_t argc, switch (args[i].kind) { case EJIT_OPERAND_GPR: { assert(ejit_int_type(args[i].type)); - emit_insn_ar(f, PARAM, i, args[i].type, EJIT_GPR(args[i].r)); + emit_insn_ar(f, EJIT_OP_PARAM, i, args[i].type, EJIT_GPR(args[i].r)); break; } case EJIT_OPERAND_FPR: { assert(ejit_float_type(args[i].type)); - emit_insn_af(f, PARAM_F, i, args[i].type, EJIT_FPR(args[i].r)); + emit_insn_af(f, EJIT_OP_PARAM_F, i, args[i].type, EJIT_FPR(args[i].r)); break; } default: abort(); } } - emit_insn_o(f, START); + emit_insn_o(f, EJIT_OP_START); return f; } @@ -388,7 +399,7 @@ void ejit_select_compile_func(struct ejit_func *f, size_t gpr, size_t fpr, bool use_64, bool try_jit, bool im_scawed) { /* emit a final end instruction in case user didn't do a return */ - emit_insn_o(f, END); + emit_insn_o(f, EJIT_OP_END); /* user can get some sanity checking done by passing these explicitly */ assert(gpr >= gpr_stats_len(&f->gpr)); @@ -403,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, NULL, false, &labels); + ejit_run(f, 0, NULL, &labels); foreach_vec(ii, f->insns) { struct ejit_insn i = *insns_at(&f->insns, ii); @@ -445,730 +456,819 @@ 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, - const struct ejit_operand args[argc]) +void ejit_taili(struct ejit_func *s, struct ejit_func *f, + size_t argc, const struct ejit_operand args[argc]) { + assert(s->rtype == f->rtype); + + s->max_args = argc > s->max_args ? argc : s->max_args; check_operands(f, argc, args); + 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, 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; + case EJIT_OPERAND_GPR: + gpr_args++; + emit_insn_ar(s, EJIT_OP_ARG, i, args[i].type, EJIT_GPR(args[i].r)); + break; + + case EJIT_OPERAND_FPR: + fpr_args++; + emit_insn_af(s, EJIT_OP_ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); + break; + + case EJIT_OPERAND_IMM: + gpr_args++; + emit_insn_ai(s, EJIT_OP_ARG_I, i, args[i].type, args[i].r); + break; + + case EJIT_OPERAND_FLT: + fpr_args++; + emit_insn_ad(s, EJIT_OP_ARG_FI, i, args[i].type, args[i].d); + break; + default: abort(); } } - emit_insn_op(s, CALLI_I, f); + assert(gpr_args <= 2 && fpr_args == 0 + && "only 2 gpr args and 0 fpr args supported in tail calls for now"); + emit_insn_op(s, EJIT_OP_TAILI, f); } -void ejit_calli_l(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->use_64 = true; - check_operands(f, argc, args); + s->max_args = argc > s->max_args ? argc : s->max_args; + /* operands must match */ + check_operands(s, argc, args); + + 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, 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; + case EJIT_OPERAND_GPR: + gpr_args++; + emit_insn_ar(s, EJIT_OP_ARG, i, args[i].type, EJIT_GPR(args[i].r)); + break; + + case EJIT_OPERAND_FPR: + fpr_args++; + emit_insn_af(s, EJIT_OP_ARG_F, i, args[i].type, EJIT_FPR(args[i].r)); + break; + + case EJIT_OPERAND_IMM: + gpr_args++; + emit_insn_ai(s, EJIT_OP_ARG_I, i, args[i].type, args[i].r); + break; + + case EJIT_OPERAND_FLT: + fpr_args++; + emit_insn_ad(s, EJIT_OP_ARG_FI, i, args[i].type, args[i].d); + break; + default: abort(); } } - emit_insn_op(s, CALLI_L, 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_f(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); 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; + 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, CALLI_F, f); + emit_insn_op(s, EJIT_OP_CALLI, f); } -void ejit_calli_d(struct ejit_func *s, struct ejit_func *f, size_t argc, - const struct ejit_operand args[argc]) +static void ejit_callr(struct ejit_func *s, enum ejit_opcode op, struct ejit_gpr target, + size_t argc, const struct ejit_operand args[argc]) { - check_operands(f, argc, args); + s->use_64 = op == EJIT_OP_CALLR_L; + s->max_args = argc > s->max_args ? argc : s->max_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; + 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, CALLI_D, f); + emit_insn_oxr(s, op, target); } -void ejit_escapei_i(struct ejit_func *s, ejit_escape_i_t f, size_t argc, - const struct ejit_operand args[argc]) +void ejit_callr_i(struct ejit_func *s, struct ejit_gpr target, + 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(); - } - } + ejit_callr(s, EJIT_OP_CALLR_I, target, argc, args); +} - emit_insn_op(s, ESCAPEI_I, f); +void ejit_callr_l(struct ejit_func *s, struct ejit_gpr target, + size_t argc, const struct ejit_operand args[argc]) +{ + ejit_callr(s, EJIT_OP_CALLR_L, target, argc, args); } -void ejit_escapei_l(struct ejit_func *s, ejit_escape_l_t f, size_t argc, - const struct ejit_operand args[argc]) +void ejit_callr_f(struct ejit_func *s, struct ejit_gpr target, + 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; - 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(); - } - } + ejit_callr(s, EJIT_OP_CALLR_F, target, argc, args); +} - emit_insn_op(s, ESCAPEI_L, f); +void ejit_callr_d(struct ejit_func *s, struct ejit_gpr target, + size_t argc, const struct ejit_operand args[argc]) +{ + ejit_callr(s, EJIT_OP_CALLR_D, target, argc, args); } -void ejit_escapei_f(struct ejit_func *s, ejit_escape_f_t f, size_t argc, - const struct ejit_operand args[argc]) +static void ejit_escapei(struct ejit_func *s, enum ejit_opcode op, void *f, + size_t argc, const struct ejit_operand args[argc]) { + s->use_64 = op == EJIT_OP_ESCAPEI_L; + s->max_args = argc > s->max_args ? argc : s->max_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; + 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, ESCAPEI_F, f); + emit_insn_op(s, op, f); } -void ejit_escapei_d(struct ejit_func *s, ejit_escape_d_t f, size_t argc, - const struct ejit_operand args[argc]) +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; - 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(); - } - } + ejit_escapei(s, EJIT_OP_ESCAPEI_I, f, argc, args); +} + +void ejit_escapei_l(struct ejit_func *s, ejit_escape_l_t f, + size_t argc, const struct ejit_operand args[argc]) +{ + ejit_escapei(s, EJIT_OP_ESCAPEI_L, f, argc, args); +} - emit_insn_op(s, ESCAPEI_D, f); +void ejit_escapei_f(struct ejit_func *s, ejit_escape_f_t f, + size_t argc, const struct ejit_operand args[argc]) +{ + ejit_escapei(s, EJIT_OP_ESCAPEI_F, f, argc, args); +} + +void ejit_escapei_d(struct ejit_func *s, ejit_escape_d_t f, + size_t argc, const struct ejit_operand args[argc]) +{ + ejit_escapei(s, EJIT_OP_ESCAPEI_D, f, argc, args); } void ejit_retval(struct ejit_func *s, struct ejit_gpr r0) { - emit_insn_or(s, RETVAL, r0); + emit_insn_or(s, EJIT_OP_RETVAL, r0); } void ejit_retval_f(struct ejit_func *s, struct ejit_fpr f0) { - emit_insn_of(s, RETVAL_F, f0); + emit_insn_of(s, EJIT_OP_RETVAL_F, f0); } void ejit_retval_d(struct ejit_func *s, struct ejit_fpr f0) { - emit_insn_of(s, RETVAL_D, f0); + emit_insn_of(s, EJIT_OP_RETVAL_D, f0); } void ejit_sti_8(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, STI8, r0, p); + emit_insn_orp(s, EJIT_OP_STI8, r0, p); } void ejit_sti_16(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, STI16, r0, p); + emit_insn_orp(s, EJIT_OP_STI16, r0, p); } void ejit_sti_32(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, STI32, r0, p); + emit_insn_orp(s, EJIT_OP_STI32, r0, p); } void ejit_sti_64(struct ejit_func *s, struct ejit_gpr r0, void *p) { s->use_64 = true; - emit_insn_orp(s, STI64, r0, p); + emit_insn_orp(s, EJIT_OP_STI64, r0, p); } void ejit_sti_f(struct ejit_func *s, struct ejit_fpr f0, void *p) { - emit_insn_ofp(s, STIF, f0, p); + emit_insn_ofp(s, EJIT_OP_STIF, f0, p); } void ejit_sti_d(struct ejit_func *s, struct ejit_fpr f0, void *p) { - emit_insn_ofp(s, STID, f0, p); + emit_insn_ofp(s, EJIT_OP_STID, f0, p); } void ejit_stxi_8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, STXI8, r0, r1, o); + emit_insn_orri(s, EJIT_OP_STXI8, r0, r1, o); } void ejit_stxi_16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, STXI16, r0, r1, o); + emit_insn_orri(s, EJIT_OP_STXI16, r0, r1, o); } void ejit_stxi_32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, STXI32, r0, r1, o); + emit_insn_orri(s, EJIT_OP_STXI32, r0, r1, o); } void ejit_stxi_64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { s->use_64 = true; - emit_insn_orri(s, STXI64, r0, r1, o); + emit_insn_orri(s, EJIT_OP_STXI64, r0, r1, o); } void ejit_stxi_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, int64_t o) { - emit_insn_ofri(s, STXIF, f0, r1, o); + emit_insn_ofri(s, EJIT_OP_STXIF, f0, r1, o); } void ejit_stxi_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, int64_t o) { - emit_insn_ofri(s, STXID, f0, r1, o); + emit_insn_ofri(s, EJIT_OP_STXID, f0, r1, o); } void ejit_stxr_8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, STXR8, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_STXR8, r0, r1, r2); } void ejit_stxr_16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, STXR16, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_STXR16, r0, r1, r2); } void ejit_stxr_32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, STXR32, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_STXR32, r0, r1, r2); } void ejit_stxr_64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { s->use_64 = true; - emit_insn_orrr(s, STXR64, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_STXR64, r0, r1, r2); } void ejit_stxr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_ofrr(s, STXRF, f0, r1, r2); + emit_insn_ofrr(s, EJIT_OP_STXRF, f0, r1, r2); } void ejit_stxr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_ofrr(s, STXRD, f0, r1, r2); + emit_insn_ofrr(s, EJIT_OP_STXRD, f0, r1, r2); } void ejit_ldi_i8(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, LDI8, r0, p); + emit_insn_orp(s, EJIT_OP_LDI8, r0, p); } void ejit_ldi_i16(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, LDI16, r0, p); + emit_insn_orp(s, EJIT_OP_LDI16, r0, p); } void ejit_ldi_i32(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, LDI32, r0, p); + emit_insn_orp(s, EJIT_OP_LDI32, r0, p); } void ejit_ldi_i64(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, LDI64, r0, p); + emit_insn_orp(s, EJIT_OP_LDI64, r0, p); } void ejit_ldi_u8(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, LDIU8, r0, p); + emit_insn_orp(s, EJIT_OP_LDIU8, r0, p); } void ejit_ldi_u16(struct ejit_func *s, struct ejit_gpr r0, void *p) { - emit_insn_orp(s, LDIU16, r0, p); + emit_insn_orp(s, EJIT_OP_LDIU16, r0, 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); + emit_insn_orp(s, EJIT_OP_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); + emit_insn_orp(s, EJIT_OP_LDIU64, r0, p); } void ejit_ldi_f(struct ejit_func *s, struct ejit_fpr f0, void *p) { - emit_insn_ofp(s, LDIF, f0, p); + emit_insn_ofp(s, EJIT_OP_LDIF, f0, p); } void ejit_ldi_d(struct ejit_func *s, struct ejit_fpr f0, void *p) { - emit_insn_ofp(s, LDID, f0, p); + emit_insn_ofp(s, EJIT_OP_LDID, f0, p); } void ejit_ldxi_i8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXI8, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXI8, r0, r1, o); } void ejit_ldxi_i16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXI16, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXI16, r0, r1, o); } void ejit_ldxi_i32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXI32, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXI32, r0, r1, o); } void ejit_ldxi_i64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXI64, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXI64, r0, r1, o); } void ejit_ldxi_u8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXIU8, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXIU8, r0, r1, o); } void ejit_ldxi_u16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXIU16, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXIU16, r0, r1, o); } void ejit_ldxi_u32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXIU32, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXIU32, r0, r1, o); } void ejit_ldxi_u64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LDXIU64, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LDXIU64, r0, r1, o); } void ejit_ldxi_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, int64_t o) { - emit_insn_ofri(s, LDXIF, f0, r1, o); + emit_insn_ofri(s, EJIT_OP_LDXIF, f0, r1, o); } void ejit_ldxi_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, int64_t o) { - emit_insn_ofri(s, LDXID, f0, r1, o); + emit_insn_ofri(s, EJIT_OP_LDXID, f0, r1, o); } void ejit_ldxr_i8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXR8, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXR8, r0, r1, r2); } void ejit_ldxr_i16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXR16, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXR16, r0, r1, r2); } void ejit_ldxr_i32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXR32, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXR32, r0, r1, r2); } void ejit_ldxr_i64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXR64, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXR64, r0, r1, r2); } void ejit_ldxr_u8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXRU8, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXRU8, r0, r1, r2); } void ejit_ldxr_u16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXRU16, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXRU16, r0, r1, r2); } void ejit_ldxr_u32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXRU32, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXRU32, r0, r1, r2); } void ejit_ldxr_u64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LDXIU64, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LDXIU64, r0, r1, r2); } void ejit_ldxr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_ofrr(s, LDXRF, f0, r1, r2); + emit_insn_ofrr(s, EJIT_OP_LDXRF, f0, r1, r2); } void ejit_ldxr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_ofrr(s, LDXRD, f0, r1, r2); + emit_insn_ofrr(s, EJIT_OP_LDXRD, f0, r1, r2); } void ejit_ret(struct ejit_func *s) { - emit_insn_o(s, END); + emit_insn_o(s, EJIT_OP_END); } void ejit_retr(struct ejit_func *s, struct ejit_gpr r0) { - emit_insn_oxr(s, RETR, r0); + assert(s->rtype != EJIT_FLOAT && s->rtype != EJIT_DOUBLE); + emit_insn_oxr(s, EJIT_OP_RETR, r0); } void ejit_retr_f(struct ejit_func *s, struct ejit_fpr f0) { - emit_insn_oxf(s, RETR_F, f0); + assert(s->rtype == EJIT_FLOAT); + emit_insn_oxf(s, EJIT_OP_RETR_F, f0); } void ejit_retr_d(struct ejit_func *s, struct ejit_fpr f0) { - emit_insn_oxf(s, RETR_D, f0); + assert(s->rtype == EJIT_DOUBLE); + emit_insn_oxf(s, EJIT_OP_RETR_D, f0); } void ejit_reti(struct ejit_func *s, int64_t i) { - emit_insn_oi(s, RETI, i); + assert(s->rtype != EJIT_FLOAT && s->rtype != EJIT_DOUBLE); + emit_insn_oi(s, EJIT_OP_RETI, i); } void ejit_reti_f(struct ejit_func *s, float f) { - emit_insn_oF(s, RETI_F, f); + assert(s->rtype == EJIT_FLOAT); + emit_insn_oF(s, EJIT_OP_RETI_F, f); } void ejit_reti_d(struct ejit_func *s, double f) { - emit_insn_oD(s, RETI_D, f); + assert(s->rtype == EJIT_DOUBLE); + emit_insn_oD(s, EJIT_OP_RETI_D, f); } void ejit_extr_8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { - emit_insn_orr(s, EXTR8, r0, r1); + emit_insn_orr(s, EJIT_OP_EXTR8, r0, r1); } void ejit_extr_16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { - emit_insn_orr(s, EXTR16, r0, r1); + emit_insn_orr(s, EJIT_OP_EXTR16, r0, 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); + emit_insn_orr(s, EJIT_OP_EXTR32, r0, r1); } void ejit_extr_u8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { - emit_insn_orr(s, EXTRU8, r0, r1); + emit_insn_orr(s, EJIT_OP_EXTRU8, r0, r1); } void ejit_extr_u16(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { - emit_insn_orr(s, EXTRU16, r0, r1); + emit_insn_orr(s, EJIT_OP_EXTRU16, r0, 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); + emit_insn_orr(s, EJIT_OP_EXTRU32, r0, r1); } void ejit_extr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1) { - emit_insn_ofr(s, EXTRF, f0, r1); + emit_insn_ofr(s, EJIT_OP_EXTRF, f0, r1); } void ejit_extr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_gpr r1) { - emit_insn_ofr(s, EXTRD, f0, r1); + emit_insn_ofr(s, EJIT_OP_EXTRD, f0, r1); } void ejit_addr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, ADDR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_ADDR, r0, r1, r2); } void ejit_addr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, ADDR_F, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_ADDR_F, f0, f1, f2); } void ejit_addr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, ADDR_D, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_ADDR_D, f0, f1, f2); } void ejit_addi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, ADDI, r0, r1, o); + emit_insn_orri(s, EJIT_OP_ADDI, r0, r1, o); } void ejit_absr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { - emit_insn_off(s, ABSR_F, f0, f1); + emit_insn_off(s, EJIT_OP_ABSR_F, f0, f1); } void ejit_absr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { - emit_insn_off(s, ABSR_D, f0, f1); + emit_insn_off(s, EJIT_OP_ABSR_D, f0, f1); } void ejit_subr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, SUBR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_SUBR, r0, r1, r2); } void ejit_subr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, SUBR_F, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_SUBR_F, f0, f1, f2); } void ejit_subr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, SUBR_D, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_SUBR_D, f0, f1, f2); } void ejit_subi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, SUBI, r0, r1, o); + emit_insn_orri(s, EJIT_OP_SUBI, r0, r1, o); } void ejit_mulr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, MULR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_MULR, r0, r1, r2); } void ejit_mulr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, MULR_F, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_MULR_F, f0, f1, f2); } void ejit_mulr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, MULR_D, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_MULR_D, f0, f1, f2); } void ejit_divr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, DIVR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_DIVR, r0, r1, r2); } void ejit_divr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, DIVR_U, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_DIVR_U, r0, r1, r2); } void ejit_divr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, DIVR_F, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_DIVR_F, f0, f1, f2); } void ejit_divr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_offf(s, DIVR_D, f0, f1, f2); + emit_insn_offf(s, EJIT_OP_DIVR_D, f0, f1, f2); } void ejit_remr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, REMR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_REMR, r0, r1, r2); } void ejit_remr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, REMR_U, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_REMR_U, r0, r1, r2); } void ejit_lshi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, LSHI, r0, r1, o); + emit_insn_orri(s, EJIT_OP_LSHI, r0, r1, o); } void ejit_lshr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, LSHR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_LSHR, r0, r1, r2); } void ejit_rshi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, RSHI, r0, r1, o); + emit_insn_orri(s, EJIT_OP_RSHI, r0, r1, o); } void ejit_rshi_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, RSHI_U, r0, r1, o); + emit_insn_orri(s, EJIT_OP_RSHI_U, r0, r1, o); } void ejit_rshr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, RSHR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_RSHR, r0, r1, r2); } void ejit_rshr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, RSHR_U, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_RSHR_U, r0, r1, r2); } void ejit_andr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, ANDR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_ANDR, r0, r1, r2); } void ejit_andi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, ANDI, r0, r1, o); + emit_insn_orri(s, EJIT_OP_ANDI, r0, r1, o); } void ejit_orr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, ORR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_ORR, r0, r1, r2); } void ejit_ori(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, ORI, r0, r1, o); + emit_insn_orri(s, EJIT_OP_ORI, r0, r1, o); } void ejit_xorr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, XORR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_XORR, r0, r1, r2); } void ejit_xori(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, int64_t o) { - emit_insn_orri(s, XORI, r0, r1, o); + emit_insn_orri(s, EJIT_OP_XORI, r0, r1, o); } void ejit_comr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { - emit_insn_orr(s, COMR, r0, r1); + emit_insn_orr(s, EJIT_OP_COMR, r0, r1); } void ejit_negr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { - emit_insn_orr(s, NEGR, r0, r1); + emit_insn_orr(s, EJIT_OP_NEGR, r0, r1); } void ejit_negr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { - emit_insn_off(s, NEGR_F, f0, f1); + emit_insn_off(s, EJIT_OP_NEGR_F, f0, f1); } void ejit_negr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { - emit_insn_off(s, NEGR_D, f0, f1); + emit_insn_off(s, EJIT_OP_NEGR_D, f0, f1); } void ejit_movi(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { - emit_insn_ori(s, MOVI, r0, o); + emit_insn_ori(s, EJIT_OP_MOVI, r0, o); } void ejit_movi_f(struct ejit_func *s, struct ejit_fpr f0, float o) { - emit_insn_ofF(s, MOVI_F, f0, o); + emit_insn_ofF(s, EJIT_OP_MOVI_F, f0, o); } void ejit_movi_d(struct ejit_func *s, struct ejit_fpr f0, double o) { - emit_insn_ofD(s, MOVI_D, f0, o); + emit_insn_ofD(s, EJIT_OP_MOVI_D, f0, o); } void ejit_movr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) @@ -1176,7 +1276,7 @@ void ejit_movr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) if (r0.r == r1.r) return; - emit_insn_orr(s, MOVR, r0, r1); + emit_insn_orr(s, EJIT_OP_MOVR, r0, r1); } void ejit_movr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) @@ -1184,7 +1284,7 @@ void ejit_movr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) if (f0.f == f1.f) return; - emit_insn_off(s, MOVR_F, f0, f1); + emit_insn_off(s, EJIT_OP_MOVR_F, f0, f1); } void ejit_movr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) @@ -1192,179 +1292,209 @@ void ejit_movr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) if (f0.f == f1.f) return; - emit_insn_off(s, MOVR_D, f0, f1); + emit_insn_off(s, EJIT_OP_MOVR_D, f0, f1); } void ejit_eqr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, EQR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_EQR, r0, r1, r2); } void ejit_eqr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, EQR_F, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_EQR_F, r0, f1, f2); } void ejit_eqr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, EQR_D, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_EQR_D, r0, f1, f2); } void ejit_ner(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, NER, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_NER, r0, r1, r2); } void ejit_ner_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, NER_F, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_NER_F, r0, f1, f2); } void ejit_ner_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, NER_D, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_NER_D, r0, f1, f2); } void ejit_gtr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GTR, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_GTR, r0, r1, r2); } void ejit_gtr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GTR_U, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_GTR_U, r0, r1, r2); } void ejit_gtr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GTR_F, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_GTR_F, r0, f1, f2); } void ejit_gtr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GTR_D, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_GTR_D, r0, f1, f2); } void ejit_ltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GTR, r0, r2, r1); + emit_insn_orrr(s, EJIT_OP_GTR, r0, r2, r1); } void ejit_ltr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GTR_U, r0, r2, r1); + emit_insn_orrr(s, EJIT_OP_GTR_U, r0, r2, r1); } void ejit_ltr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GTR_F, r0, f2, f1); + emit_insn_orff(s, EJIT_OP_GTR_F, r0, f2, f1); } void ejit_ltr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GTR_D, r0, f2, f1); + emit_insn_orff(s, EJIT_OP_GTR_D, r0, f2, f1); } void ejit_ger(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GER, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_GER, r0, r1, r2); } void ejit_ger_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GER_U, r0, r1, r2); + emit_insn_orrr(s, EJIT_OP_GER_U, r0, r1, r2); } void ejit_ger_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GER_F, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_GER_F, r0, f1, f2); } void ejit_ger_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GER_D, r0, f1, f2); + emit_insn_orff(s, EJIT_OP_GER_D, r0, f1, f2); } void ejit_ler(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GER, r0, r2, r1); + emit_insn_orrr(s, EJIT_OP_GER, r0, r2, r1); } void ejit_ler_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1, struct ejit_gpr r2) { - emit_insn_orrr(s, GER_U, r0, r2, r1); + emit_insn_orrr(s, EJIT_OP_GER_U, r0, r2, r1); } void ejit_ler_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GER_F, r0, f2, f1); + emit_insn_orff(s, EJIT_OP_GER_F, r0, f2, f1); } void ejit_ler_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1, struct ejit_fpr f2) { - emit_insn_orff(s, GER_D, r0, f2, f1); + emit_insn_orff(s, EJIT_OP_GER_D, r0, f2, f1); } void ejit_truncr_d_32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1) { - emit_insn_orf(s, TRUNCR_D_32, r0, f1); + emit_insn_orf(s, EJIT_OP_TRUNCR_D_32, r0, f1); } void ejit_truncr_d_64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1) { s->use_64 = true; - emit_insn_orf(s, TRUNCR_D_64, r0, f1); + emit_insn_orf(s, EJIT_OP_TRUNCR_D_64, r0, f1); } void ejit_truncr_f_32(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1) { - emit_insn_orf(s, TRUNCR_F_32, r0, f1); + emit_insn_orf(s, EJIT_OP_TRUNCR_F_32, r0, f1); } void ejit_truncr_f_64(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr f1) { s->use_64 = true; - emit_insn_orf(s, TRUNCR_F_64, r0, f1); + emit_insn_orf(s, EJIT_OP_TRUNCR_F_64, r0, f1); +} + +void ejit_sqrtr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1) +{ + emit_insn_off(s, EJIT_OP_SQRTR_F, r0, r1); +} + +void ejit_sqrtr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1) +{ + emit_insn_off(s, EJIT_OP_SQRTR_D, r0, r1); +} + +void ejit_minr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2) +{ + emit_insn_offf(s, EJIT_OP_MINR_F, r0, r1, r2); +} + +void ejit_minr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2) +{ + emit_insn_offf(s, EJIT_OP_MINR_D, r0, r1, r2); +} + +void ejit_maxr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2) +{ + emit_insn_offf(s, EJIT_OP_MAXR_F, r0, r1, r2); +} + +void ejit_maxr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1, struct ejit_fpr r2) +{ + emit_insn_offf(s, EJIT_OP_MAXR_D, r0, r1, r2); } struct ejit_reloc ejit_bner(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BNER, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BNER, r0, r1); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_bnei(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BNEI, r0, o); + emit_insn_oxri(s, EJIT_OP_BNEI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1372,7 +1502,7 @@ struct ejit_reloc ejit_bner_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BNER_F, f0, f1); + emit_insn_oxff(s, EJIT_OP_BNER_F, f0, f1); return (struct ejit_reloc){.insn = addr}; } @@ -1380,7 +1510,7 @@ struct ejit_reloc ejit_bner_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BNER_D, f0, f1); + emit_insn_oxff(s, EJIT_OP_BNER_D, f0, f1); return (struct ejit_reloc){.insn = addr}; } @@ -1388,14 +1518,14 @@ struct ejit_reloc ejit_beqr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BEQR, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BEQR, r0, r1); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_beqi(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BEQI, r0, o); + emit_insn_oxri(s, EJIT_OP_BEQI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1403,7 +1533,7 @@ struct ejit_reloc ejit_beqr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BEQR_F, f0, f1); + emit_insn_oxff(s, EJIT_OP_BEQR_F, f0, f1); return (struct ejit_reloc){.insn = addr}; } @@ -1411,7 +1541,7 @@ struct ejit_reloc ejit_beqr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BEQR_D, f0, f1); + emit_insn_oxff(s, EJIT_OP_BEQR_D, f0, f1); return (struct ejit_reloc){.insn = addr}; } @@ -1419,7 +1549,7 @@ struct ejit_reloc ejit_bger(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGER, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BGER, r0, r1); return (struct ejit_reloc){.insn = addr}; } @@ -1427,7 +1557,7 @@ struct ejit_reloc ejit_bger_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGER_U, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BGER_U, r0, r1); return (struct ejit_reloc){.insn = addr}; } @@ -1435,7 +1565,7 @@ struct ejit_reloc ejit_bger_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGER_F, f0, f1); + emit_insn_oxff(s, EJIT_OP_BGER_F, f0, f1); return (struct ejit_reloc){.insn = addr}; } @@ -1443,14 +1573,14 @@ struct ejit_reloc ejit_bger_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGER_D, f0, f1); + emit_insn_oxff(s, EJIT_OP_BGER_D, f0, f1); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_bgei(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BGEI, r0, o); + emit_insn_oxri(s, EJIT_OP_BGEI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1458,7 +1588,7 @@ struct ejit_reloc ejit_bgei_u(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BGEI_U, r0, o); + emit_insn_oxri(s, EJIT_OP_BGEI_U, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1466,7 +1596,7 @@ struct ejit_reloc ejit_bler(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGER, r1, r0); + emit_insn_oxrr(s, EJIT_OP_BGER, r1, r0); return (struct ejit_reloc){.insn = addr}; } @@ -1474,7 +1604,7 @@ struct ejit_reloc ejit_bler_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGER_U, r1, r0); + emit_insn_oxrr(s, EJIT_OP_BGER_U, r1, r0); return (struct ejit_reloc){.insn = addr}; } @@ -1482,7 +1612,7 @@ struct ejit_reloc ejit_bler_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGER_F, f1, f0); + emit_insn_oxff(s, EJIT_OP_BGER_F, f1, f0); return (struct ejit_reloc){.insn = addr}; } @@ -1490,14 +1620,14 @@ struct ejit_reloc ejit_bler_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGER_D, f1, f0); + emit_insn_oxff(s, EJIT_OP_BGER_D, f1, f0); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_blei(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BLEI, r0, o); + emit_insn_oxri(s, EJIT_OP_BLEI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1505,14 +1635,14 @@ struct ejit_reloc ejit_blei_u(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BLEI_U, r0, o); + emit_insn_oxri(s, EJIT_OP_BLEI_U, r0, o); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_bgti(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BGTI, r0, o); + emit_insn_oxri(s, EJIT_OP_BGTI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1520,7 +1650,7 @@ struct ejit_reloc ejit_bgti_u(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BGTI_U, r0, o); + emit_insn_oxri(s, EJIT_OP_BGTI_U, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1528,7 +1658,7 @@ struct ejit_reloc ejit_bgtr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGTR, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BGTR, r0, r1); return (struct ejit_reloc){.insn = addr}; } @@ -1536,7 +1666,7 @@ struct ejit_reloc ejit_bgtr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGTR_U, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BGTR_U, r0, r1); return (struct ejit_reloc){.insn = addr}; } @@ -1544,7 +1674,7 @@ struct ejit_reloc ejit_bgtr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGTR_F, f0, f1); + emit_insn_oxff(s, EJIT_OP_BGTR_F, f0, f1); return (struct ejit_reloc){.insn = addr}; } @@ -1552,7 +1682,7 @@ struct ejit_reloc ejit_bgtr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGTR_D, f0, f1); + emit_insn_oxff(s, EJIT_OP_BGTR_D, f0, f1); return (struct ejit_reloc){.insn = addr}; } @@ -1560,7 +1690,7 @@ struct ejit_reloc ejit_bltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGTR, r1, r0); + emit_insn_oxrr(s, EJIT_OP_BGTR, r1, r0); return (struct ejit_reloc){.insn = addr}; } @@ -1568,7 +1698,7 @@ struct ejit_reloc ejit_bltr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BGTR_U, r1, r0); + emit_insn_oxrr(s, EJIT_OP_BGTR_U, r1, r0); return (struct ejit_reloc){.insn = addr}; } @@ -1576,7 +1706,7 @@ struct ejit_reloc ejit_bltr_f(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGTR_F, f1, f0); + emit_insn_oxff(s, EJIT_OP_BGTR_F, f1, f0); return (struct ejit_reloc){.insn = addr}; } @@ -1584,14 +1714,14 @@ struct ejit_reloc ejit_bltr_d(struct ejit_func *s, struct ejit_fpr f0, struct ejit_fpr f1) { size_t addr = insns_len(&s->insns); - emit_insn_oxff(s, BGTR_D, f1, f0); + emit_insn_oxff(s, EJIT_OP_BGTR_D, f1, f0); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_blti(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BLTI, r0, o); + emit_insn_oxri(s, EJIT_OP_BLTI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1599,28 +1729,28 @@ struct ejit_reloc ejit_blti_u(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BLTI_U, r0, o); + emit_insn_oxri(s, EJIT_OP_BLTI_U, r0, o); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_jmp(struct ejit_func *s) { size_t addr = insns_len(&s->insns); - emit_insn_o(s, JMP); + emit_insn_o(s, EJIT_OP_JMP); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_jmpr(struct ejit_func *s, struct ejit_gpr r0) { size_t addr = insns_len(&s->insns); - emit_insn_oxr(s, JMPR, r0); + emit_insn_oxr(s, EJIT_OP_JMPR, r0); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_bmci(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BMCI, r0, o); + emit_insn_oxri(s, EJIT_OP_BMCI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1628,14 +1758,14 @@ struct ejit_reloc ejit_bmcr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BMCR, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BMCR, r0, r1); return (struct ejit_reloc){.insn = addr}; } struct ejit_reloc ejit_bmsi(struct ejit_func *s, struct ejit_gpr r0, int64_t o) { size_t addr = insns_len(&s->insns); - emit_insn_oxri(s, BMSI, r0, o); + emit_insn_oxri(s, EJIT_OP_BMSI, r0, o); return (struct ejit_reloc){.insn = addr}; } @@ -1643,27 +1773,12 @@ struct ejit_reloc ejit_bmsr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1) { size_t addr = insns_len(&s->insns); - emit_insn_oxrr(s, BMSR, r0, r1); + emit_insn_oxrr(s, EJIT_OP_BMSR, r0, r1); return (struct ejit_reloc){.insn = addr}; } -static struct interp_state create_interp_state() -{ - struct interp_state state; - state.gprs = gprs_create(); - state.fprs = fprs_create(); - state.args = args_create(); - return state; -} - -static void destroy_interp_state(struct interp_state state) -{ - gprs_destroy(&state.gprs); - fprs_destroy(&state.fprs); - args_destroy(&state.args); -} - -long ejit_run_func_ctx_i(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx) +long ejit_run_func_i(struct ejit_func *f, size_t argc, + struct ejit_arg args[argc]) { check_args(f, argc, args); assert((f->rtype == EJIT_VOID || ejit_int_type(f->rtype)) @@ -1672,64 +1787,29 @@ long ejit_run_func_ctx_i(struct ejit_func *f, size_t argc, struct ejit_arg args[ #endif ); - return ejit_run(f, argc, args, ctx, true, NULL).i; + return ejit_run(f, argc, args, NULL).i; } -long ejit_run_func_i(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]) { - 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 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_l(struct ejit_func *f, size_t argc, - struct ejit_arg args[argc]) -{ - struct interp_state state = create_interp_state(); - int64_t r = ejit_run_func_ctx_l(f, argc, args, &state); - destroy_interp_state(state); - return r; + return ejit_run(f, argc, args, NULL).i; } -float ejit_run_func_ctx_f(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *ctx) +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, ctx, true, NULL).f; + return ejit_run(f, argc, args, NULL).f; } -float ejit_run_func_f(struct ejit_func *f, size_t argc, - struct ejit_arg args[argc]) -{ - 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) +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, 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_func_ctx_d(f, argc, args, &state); - destroy_interp_state(state); - return r; + 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]) @@ -1748,6 +1828,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), @@ -1756,7 +1840,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 f8ba927..894be30 100644 --- a/src/interp.c +++ b/src/interp.c @@ -5,262 +5,270 @@ /* this is the body of a given ejit_interp function, it assumes there's an * external int64_t retval and double retval_f into which it places the value to * be returned. Included from src/interp.c */ -union interp_ret ejit_run(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_run(struct ejit_func *f, size_t paramc, struct ejit_arg params[paramc], void ***labels_wb) { - static void *labels[OPCODE_COUNT] = { - [MOVI] = &&MOVI, - [MOVI_F] = &&MOVI_F, - [MOVI_D] = &&MOVI_D, - [MOVR] = &&MOVR, - [MOVR_F] = &&MOVR_F, - [MOVR_D] = &&MOVR_D, - - [EXTR8] = &&EXTR8, - [EXTR16] = &&EXTR16, - [EXTR32] = &&EXTR32, - [EXTRU8] = &&EXTRU8, - [EXTRU16] = &&EXTRU16, - [EXTRU32] = &&EXTRU32, - [EXTRF] = &&EXTRF, - [EXTRD] = &&EXTRD, - - [ADDR] = &&ADDR, - [ADDR_F] = &&ADDR_F, - [ADDR_D] = &&ADDR_D, - [ADDI] = &&ADDI, - - [ABSR_F] = &&ABSR_F, - [ABSR_D] = &&ABSR_D, - - [SUBR] = &&SUBR, - [SUBR_F] = &&SUBR_F, - [SUBR_D] = &&SUBR_D, - [SUBI] = &&SUBI, - - [MULR] = &&MULR, - [MULR_F] = &&MULR_F, - [MULR_D] = &&MULR_D, - - [DIVR] = &&DIVR, - [DIVR_U] = &&DIVR_U, - [DIVR_F] = &&DIVR_F, - [DIVR_D] = &&DIVR_D, - - [REMR] = &&REMR, - [REMR_U] = &&REMR_U, - - [LSHI] = &&LSHI, - [LSHR] = &&LSHR, - [RSHI] = &&RSHI, - [RSHR] = &&RSHR, - [RSHI_U] = &&RSHI_U, - [RSHR_U] = &&RSHR_U, - - [ANDR] = &&ANDR, - [ANDI] = &&ANDI, - - [ORR] = &&ORR, - [ORI] = &&ORI, - - [XORR] = &&XORR, - [XORI] = &&XORI, - - [COMR] = &&COMR, - [NEGR] = &&NEGR, - [NEGR_F] = &&NEGR_F, - [NEGR_D] = &&NEGR_D, - - [EQR] = &&EQR, - [EQR_F] = &&EQR_F, - [EQR_D] = &&EQR_D, - - [NER] = &&NER, - [NER_F] = &&NER_F, - [NER_D] = &&NER_D, - - [GTR] = &>R, - [GTR_U] = &>R_U, - [GTR_F] = &>R_F, - [GTR_D] = &>R_D, - - [GER] = &&GER, - [GER_U] = &&GER_U, - [GER_F] = &&GER_F, - [GER_D] = &&GER_D, - - [STI8] = &&STI8, - [STI16] = &&STI16, - [STI32] = &&STI32, - [STI64] = &&STI64, - [STIF] = &&STIF, - [STID] = &&STID, - - [STXI8] = &&STXI8, - [STXI16] = &&STXI16, - [STXI32] = &&STXI32, - [STXI64] = &&STXI64, - [STXIF] = &&STXIF, - [STXID] = &&STXID, - - [STXR8] = &&STXR8, - [STXR16] = &&STXR16, - [STXR32] = &&STXR32, - [STXR64] = &&STXR64, - [STXRF] = &&STXRF, - [STXRD] = &&STXRD, - - [LDI8] = &&LDI8, - [LDI16] = &&LDI16, - [LDI32] = &&LDI32, - [LDI64] = &&LDI64, - [LDIU8] = &&LDIU8, - [LDIU16] = &&LDIU16, - [LDIU32] = &&LDIU32, - [LDIU64] = &&LDIU64, - [LDIF] = &&LDIF, - [LDID] = &&LDID, - - [LDXI8] = &&LDXI8, - [LDXI16] = &&LDXI16, - [LDXI32] = &&LDXI32, - [LDXI64] = &&LDXI64, - [LDXIU8] = &&LDXIU8, - [LDXIU16] = &&LDXIU16, - [LDXIU32] = &&LDXIU32, - [LDXIU64] = &&LDXIU64, - [LDXIF] = &&LDXIF, - [LDXID] = &&LDXID, - - [LDXR8] = &&LDXR8, - [LDXR16] = &&LDXR16, - [LDXR32] = &&LDXR32, - [LDXR64] = &&LDXR64, - [LDXRU8] = &&LDXRU8, - [LDXRU16] = &&LDXRU16, - [LDXRU32] = &&LDXRU32, - [LDXRU64] = &&LDXRU64, - [LDXRF] = &&LDXRF, - [LDXRD] = &&LDXRD, - - [TRUNCR_D_32] = &&TRUNCR_D_32, - [TRUNCR_D_64] = &&TRUNCR_D_64, - [TRUNCR_F_32] = &&TRUNCR_F_32, - [TRUNCR_F_64] = &&TRUNCR_F_64, - - [BNER] = &&BNER, - [BNEI] = &&BNEI, - [BNER_F] = &&BNER_F, - [BNER_D] = &&BNER_D, - - [BEQR] = &&BEQR, - [BEQI] = &&BEQI, - [BEQR_F] = &&BEQR_F, - [BEQR_D] = &&BEQR_D, - - [BGER] = &&BGER, - [BGER_U] = &&BGER_U, - [BGEI] = &&BGEI, - [BGEI_U] = &&BGEI_U, - [BGER_F] = &&BGER_F, - [BGER_D] = &&BGER_D, - - [BLEI] = &&BLEI, - [BLEI_U] = &&BLEI_U, - - [BGTR] = &&BGTR, - [BGTR_U] = &&BGTR_U, - [BGTI] = &&BGTI, - [BGTI_U] = &&BGTI_U, - [BGTR_F] = &&BGTR_F, - [BGTR_D] = &&BGTR_D, - - [BLTI] = &&BLTI, - [BLTI_U] = &&BLTI_U, - - [JMP] = &&JMP, - [JMPR] = &&JMPR, - - [BMCI] = &&BMCI, - [BMCR] = &&BMCR, - [BMSI] = &&BMSI, - [BMSR] = &&BMSR, - - [RETR] = &&RETR, - [RETI] = &&RETI, - [RETR_F] = &&RETR_F, - [RETI_F] = &&RETI_F, - [RETR_D] = &&RETR_D, - [RETI_D] = &&RETI_D, - - [RETVAL] = &&RETVAL, - [RETVAL_F] = &&RETVAL_F, - [RETVAL_D] = &&RETVAL_D, - - [ARG] = &&ARG, - [ARG_I] = &&ARG_I, - [ARG_F] = &&ARG_F, - [ARG_FI] = &&ARG_FI, - - [PARAM] = &&PARAM, - [PARAM_F] = &&PARAM_F, - - [CALLI_I] = &&CALLI_I, - [CALLI_L] = &&CALLI_L, - [CALLI_F] = &&CALLI_F, - [CALLI_D] = &&CALLI_D, - [ESCAPEI_I] = &&ESCAPEI_I, - [ESCAPEI_F] = &&ESCAPEI_F, - [ESCAPEI_L] = &&ESCAPEI_L, - [ESCAPEI_D] = &&ESCAPEI_D, - - [START] = &&START, - [END] = &&END, + static void *labels[EJIT_OPCODE_COUNT] = { + [EJIT_OP_MOVI] = &&MOVI, + [EJIT_OP_MOVI_F] = &&MOVI_F, + [EJIT_OP_MOVI_D] = &&MOVI_D, + [EJIT_OP_MOVR] = &&MOVR, + [EJIT_OP_MOVR_F] = &&MOVR_F, + [EJIT_OP_MOVR_D] = &&MOVR_D, + + [EJIT_OP_EXTR8] = &&EXTR8, + [EJIT_OP_EXTR16] = &&EXTR16, + [EJIT_OP_EXTR32] = &&EXTR32, + [EJIT_OP_EXTRU8] = &&EXTRU8, + [EJIT_OP_EXTRU16] = &&EXTRU16, + [EJIT_OP_EXTRU32] = &&EXTRU32, + [EJIT_OP_EXTRF] = &&EXTRF, + [EJIT_OP_EXTRD] = &&EXTRD, + + [EJIT_OP_ADDR] = &&ADDR, + [EJIT_OP_ADDR_F] = &&ADDR_F, + [EJIT_OP_ADDR_D] = &&ADDR_D, + [EJIT_OP_ADDI] = &&ADDI, + + [EJIT_OP_ABSR_F] = &&ABSR_F, + [EJIT_OP_ABSR_D] = &&ABSR_D, + + [EJIT_OP_SUBR] = &&SUBR, + [EJIT_OP_SUBR_F] = &&SUBR_F, + [EJIT_OP_SUBR_D] = &&SUBR_D, + [EJIT_OP_SUBI] = &&SUBI, + + [EJIT_OP_MULR] = &&MULR, + [EJIT_OP_MULR_F] = &&MULR_F, + [EJIT_OP_MULR_D] = &&MULR_D, + + [EJIT_OP_DIVR] = &&DIVR, + [EJIT_OP_DIVR_U] = &&DIVR_U, + [EJIT_OP_DIVR_F] = &&DIVR_F, + [EJIT_OP_DIVR_D] = &&DIVR_D, + + [EJIT_OP_REMR] = &&REMR, + [EJIT_OP_REMR_U] = &&REMR_U, + + [EJIT_OP_LSHI] = &&LSHI, + [EJIT_OP_LSHR] = &&LSHR, + [EJIT_OP_RSHI] = &&RSHI, + [EJIT_OP_RSHR] = &&RSHR, + [EJIT_OP_RSHI_U] = &&RSHI_U, + [EJIT_OP_RSHR_U] = &&RSHR_U, + + [EJIT_OP_ANDR] = &&ANDR, + [EJIT_OP_ANDI] = &&ANDI, + + [EJIT_OP_ORR] = &&ORR, + [EJIT_OP_ORI] = &&ORI, + + [EJIT_OP_XORR] = &&XORR, + [EJIT_OP_XORI] = &&XORI, + + [EJIT_OP_COMR] = &&COMR, + [EJIT_OP_NEGR] = &&NEGR, + [EJIT_OP_NEGR_F] = &&NEGR_F, + [EJIT_OP_NEGR_D] = &&NEGR_D, + + [EJIT_OP_EQR] = &&EQR, + [EJIT_OP_EQR_F] = &&EQR_F, + [EJIT_OP_EQR_D] = &&EQR_D, + + [EJIT_OP_NER] = &&NER, + [EJIT_OP_NER_F] = &&NER_F, + [EJIT_OP_NER_D] = &&NER_D, + + [EJIT_OP_GTR] = &>R, + [EJIT_OP_GTR_U] = &>R_U, + [EJIT_OP_GTR_F] = &>R_F, + [EJIT_OP_GTR_D] = &>R_D, + + [EJIT_OP_GER] = &&GER, + [EJIT_OP_GER_U] = &&GER_U, + [EJIT_OP_GER_F] = &&GER_F, + [EJIT_OP_GER_D] = &&GER_D, + + [EJIT_OP_STI8] = &&STI8, + [EJIT_OP_STI16] = &&STI16, + [EJIT_OP_STI32] = &&STI32, + [EJIT_OP_STI64] = &&STI64, + [EJIT_OP_STIF] = &&STIF, + [EJIT_OP_STID] = &&STID, + + [EJIT_OP_STXI8] = &&STXI8, + [EJIT_OP_STXI16] = &&STXI16, + [EJIT_OP_STXI32] = &&STXI32, + [EJIT_OP_STXI64] = &&STXI64, + [EJIT_OP_STXIF] = &&STXIF, + [EJIT_OP_STXID] = &&STXID, + + [EJIT_OP_STXR8] = &&STXR8, + [EJIT_OP_STXR16] = &&STXR16, + [EJIT_OP_STXR32] = &&STXR32, + [EJIT_OP_STXR64] = &&STXR64, + [EJIT_OP_STXRF] = &&STXRF, + [EJIT_OP_STXRD] = &&STXRD, + + [EJIT_OP_LDI8] = &&LDI8, + [EJIT_OP_LDI16] = &&LDI16, + [EJIT_OP_LDI32] = &&LDI32, + [EJIT_OP_LDI64] = &&LDI64, + [EJIT_OP_LDIU8] = &&LDIU8, + [EJIT_OP_LDIU16] = &&LDIU16, + [EJIT_OP_LDIU32] = &&LDIU32, + [EJIT_OP_LDIU64] = &&LDIU64, + [EJIT_OP_LDIF] = &&LDIF, + [EJIT_OP_LDID] = &&LDID, + + [EJIT_OP_LDXI8] = &&LDXI8, + [EJIT_OP_LDXI16] = &&LDXI16, + [EJIT_OP_LDXI32] = &&LDXI32, + [EJIT_OP_LDXI64] = &&LDXI64, + [EJIT_OP_LDXIU8] = &&LDXIU8, + [EJIT_OP_LDXIU16] = &&LDXIU16, + [EJIT_OP_LDXIU32] = &&LDXIU32, + [EJIT_OP_LDXIU64] = &&LDXIU64, + [EJIT_OP_LDXIF] = &&LDXIF, + [EJIT_OP_LDXID] = &&LDXID, + + [EJIT_OP_LDXR8] = &&LDXR8, + [EJIT_OP_LDXR16] = &&LDXR16, + [EJIT_OP_LDXR32] = &&LDXR32, + [EJIT_OP_LDXR64] = &&LDXR64, + [EJIT_OP_LDXRU8] = &&LDXRU8, + [EJIT_OP_LDXRU16] = &&LDXRU16, + [EJIT_OP_LDXRU32] = &&LDXRU32, + [EJIT_OP_LDXRU64] = &&LDXRU64, + [EJIT_OP_LDXRF] = &&LDXRF, + [EJIT_OP_LDXRD] = &&LDXRD, + + [EJIT_OP_TRUNCR_D_32] = &&TRUNCR_D_32, + [EJIT_OP_TRUNCR_D_64] = &&TRUNCR_D_64, + [EJIT_OP_TRUNCR_F_32] = &&TRUNCR_F_32, + [EJIT_OP_TRUNCR_F_64] = &&TRUNCR_F_64, + + [EJIT_OP_SQRTR_F] = &&SQRTR_F, + [EJIT_OP_SQRTR_D] = &&SQRTR_D, + + [EJIT_OP_MINR_F] = &&MINR_F, + [EJIT_OP_MINR_D] = &&MINR_D, + + [EJIT_OP_MAXR_F] = &&MAXR_F, + [EJIT_OP_MAXR_D] = &&MAXR_D, + + [EJIT_OP_BNER] = &&BNER, + [EJIT_OP_BNEI] = &&BNEI, + [EJIT_OP_BNER_F] = &&BNER_F, + [EJIT_OP_BNER_D] = &&BNER_D, + + [EJIT_OP_BEQR] = &&BEQR, + [EJIT_OP_BEQI] = &&BEQI, + [EJIT_OP_BEQR_F] = &&BEQR_F, + [EJIT_OP_BEQR_D] = &&BEQR_D, + + [EJIT_OP_BGER] = &&BGER, + [EJIT_OP_BGER_U] = &&BGER_U, + [EJIT_OP_BGEI] = &&BGEI, + [EJIT_OP_BGEI_U] = &&BGEI_U, + [EJIT_OP_BGER_F] = &&BGER_F, + [EJIT_OP_BGER_D] = &&BGER_D, + + [EJIT_OP_BLEI] = &&BLEI, + [EJIT_OP_BLEI_U] = &&BLEI_U, + + [EJIT_OP_BGTR] = &&BGTR, + [EJIT_OP_BGTR_U] = &&BGTR_U, + [EJIT_OP_BGTI] = &&BGTI, + [EJIT_OP_BGTI_U] = &&BGTI_U, + [EJIT_OP_BGTR_F] = &&BGTR_F, + [EJIT_OP_BGTR_D] = &&BGTR_D, + + [EJIT_OP_BLTI] = &&BLTI, + [EJIT_OP_BLTI_U] = &&BLTI_U, + + [EJIT_OP_JMP] = &&JMP, + [EJIT_OP_JMPR] = &&JMPR, + + [EJIT_OP_BMCI] = &&BMCI, + [EJIT_OP_BMCR] = &&BMCR, + [EJIT_OP_BMSI] = &&BMSI, + [EJIT_OP_BMSR] = &&BMSR, + + [EJIT_OP_RETR] = &&RETR, + [EJIT_OP_RETI] = &&RETI, + [EJIT_OP_RETR_F] = &&RETR_F, + [EJIT_OP_RETI_F] = &&RETI_F, + [EJIT_OP_RETR_D] = &&RETR_D, + [EJIT_OP_RETI_D] = &&RETI_D, + + [EJIT_OP_RETVAL] = &&RETVAL, + [EJIT_OP_RETVAL_F] = &&RETVAL_F, + [EJIT_OP_RETVAL_D] = &&RETVAL_D, + + [EJIT_OP_ARG] = &&ARG, + [EJIT_OP_ARG_I] = &&ARG_I, + [EJIT_OP_ARG_F] = &&ARG_F, + [EJIT_OP_ARG_FI] = &&ARG_FI, + + [EJIT_OP_PARAM] = &&PARAM, + [EJIT_OP_PARAM_F] = &&PARAM_F, + + [EJIT_OP_CALLR_I] = &&CALLR_I, + [EJIT_OP_CALLR_L] = &&CALLR_L, + [EJIT_OP_CALLR_F] = &&CALLR_F, + [EJIT_OP_CALLR_D] = &&CALLR_D, + [EJIT_OP_CALLI] = &&CALLI, + + [EJIT_OP_TAILR] = &&TAILR, + [EJIT_OP_TAILI] = &&TAILI, + + [EJIT_OP_ESCAPEI_I] = &&ESCAPEI_I, + [EJIT_OP_ESCAPEI_L] = &&ESCAPEI_L, + [EJIT_OP_ESCAPEI_F] = &&ESCAPEI_F, + [EJIT_OP_ESCAPEI_D] = &&ESCAPEI_D, + + [EJIT_OP_START] = &&START, + [EJIT_OP_END] = &&END, }; - if (!run) { + if (labels_wb) { *labels_wb = labels; - goto zero_out; + return (union interp_ret){.i = 0}; } assert(f->size && "trying to run a function that hasn't been compiled"); - - if (f->arena) { + if (f->extern_call) { if (f->rtype == EJIT_INT64 || f->rtype == EJIT_UINT64) return (union interp_ret){ - .i = ((ejit_escape_l_t)f->arena)(argc, args) + .i = ((ejit_escape_l_t)f->extern_call)(paramc, params) }; if (f->rtype == EJIT_DOUBLE) return (union interp_ret){ - .f = ((ejit_escape_d_t)f->arena)(argc, args) + .f = ((ejit_escape_d_t)f->extern_call)(paramc, params) }; if (f->rtype == EJIT_FLOAT) return (union interp_ret){ - .f = ((ejit_escape_f_t)f->arena)(argc, args) + .f = ((ejit_escape_f_t)f->extern_call)(paramc, params) }; return (union interp_ret){ - .i = ((ejit_escape_i_t)f->arena)(argc, args) + .i = ((ejit_escape_i_t)f->extern_call)(paramc, params) }; } - int64_t retval = 0; double retval_f = 0.0; - - size_t prev_gprs = gprs_len(&state->gprs); - size_t prev_fprs = fprs_len(&state->fprs); - size_t prev_argc = args_len(&state->args); - - gprs_reserve(&state->gprs, prev_gprs + gpr_stats_len(&f->gpr)); - fprs_reserve(&state->fprs, prev_fprs + fpr_stats_len(&f->fpr)); - +top: + union interp_ret retval = {.i = 0}; union fpr { double d; float f; }; - int64_t *gpr = ((int64_t *)state->gprs.buf) + prev_gprs; - union fpr *fpr = ((union fpr *)state->fprs.buf) + prev_fprs; + size_t argc = 0; + int64_t gpr[gpr_stats_len(&f->gpr)]; + union fpr fpr[fpr_stats_len(&f->fpr)]; + struct ejit_arg args[f->max_args]; struct ejit_insn *insns = f->insns.buf; /* retval is kind of an unfortunate extra bit of state to keep track of, @@ -278,7 +286,7 @@ union interp_ret ejit_run(struct ejit_func *f, size_t argc, struct ejit_arg args DISPATCH(); DO(END); - goto zero_out; + return (union interp_ret){.i = 0}; DISPATCH(); DO(MOVI); @@ -789,6 +797,30 @@ union interp_ret ejit_run(struct ejit_func *f, size_t argc, struct ejit_arg args gpr[i.r0] = (int64_t)fpr[i.r1].f; DISPATCH(); + DO(SQRTR_F); + fpr[i.r0].f = sqrt(fpr[i.r1].f); + DISPATCH(); + + DO(MINR_F); + fpr[i.r0].f = fminf(fpr[i.r1].f, fpr[i.r2].f); + DISPATCH(); + + DO(MINR_D); + fpr[i.r0].d = fmin(fpr[i.r1].d, fpr[i.r2].d); + DISPATCH(); + + DO(MAXR_F); + fpr[i.r0].f = fmaxf(fpr[i.r1].f, fpr[i.r2].f); + DISPATCH(); + + DO(MAXR_D); + fpr[i.r0].d = fmax(fpr[i.r1].d, fpr[i.r2].d); + DISPATCH(); + + DO(SQRTR_D); + fpr[i.r0].d = sqrt(fpr[i.r1].d); + DISPATCH(); + DO(BNER); if (gpr[i.r1] != gpr[i.r2]) JUMP(i.r0); @@ -966,37 +998,48 @@ union interp_ret ejit_run(struct ejit_func *f, size_t argc, struct ejit_arg args DISPATCH(); DO(RETVAL); - gpr[i.r0] = retval; + gpr[i.r0] = retval.i; DISPATCH(); DO(RETVAL_F); - fpr[i.r0].f = retval_f; + fpr[i.r0].f = retval.f; DISPATCH(); DO(RETVAL_D); - fpr[i.r0].d = retval_f; + fpr[i.r0].d = retval.f; DISPATCH(); DO(PARAM); - gpr[i.r2] = args[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); if (i.r1 == EJIT_FLOAT) - fpr[i.r2].f = args[i.r0].f; + fpr[i.r2].f = params[i.r0].f; else - fpr[i.r2].d = args[i.r0].d; + fpr[i.r2].d = params[i.r0].d; DISPATCH(); DO(ARG); struct ejit_arg a = ejit_build_arg(i.r1, gpr[i.r2]); - args_append(&state->args, a); + args[argc++] = a; DISPATCH(); DO(ARG_I); struct ejit_arg a = ejit_build_arg(i.r1, i.o); - args_append(&state->args, a); + args[argc++] = a; DISPATCH(); DO(ARG_F); @@ -1006,7 +1049,7 @@ union interp_ret ejit_run(struct ejit_func *f, size_t argc, struct ejit_arg args else a = ejit_build_arg_f(i.r1, fpr[i.r2].f); - args_append(&state->args, a); + args[argc++] = a; DISPATCH(); DO(ARG_FI); @@ -1014,145 +1057,111 @@ union interp_ret ejit_run(struct ejit_func *f, size_t argc, struct ejit_arg args if (i.r1 == EJIT_DOUBLE) a = ejit_build_arg_f(i.r1, i.d); else - a = ejit_build_arg_f(i.r1, i.f); + a = ejit_build_arg_f(i.r1, i.d); - args_append(&state->args, a); + args[argc++] = a; DISPATCH(); - DO(CALLI_I); - struct ejit_func *f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; + DO(TAILI); + f = (struct ejit_func *)i.p; + + assert(!f->direct_call && "trying to interpret compiled fun"); - retval = ejit_run(f, argc, args, state, true, NULL).i; + paramc = argc; + for (size_t i = 0; i < argc; ++i) + params[i] = args[i]; - gpr = state->gprs.buf + prev_gprs; - fpr = (union fpr *)state->fprs.buf + prev_fprs; - args_shrink(&state->args, prev_argc); + goto top; DISPATCH(); - DO(CALLI_L); - struct ejit_func *f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; + DO(TAILR); + f = (struct ejit_func *)gpr[i.r1]; - retval = ejit_run(f, argc, args, state, true, NULL).i; + /** @todo we could potentially just interpret the func as a fallback + * instead of aborting here, but this is good enough for now */ + assert(!f->direct_call && "trying to interpret compiled fun"); - gpr = state->gprs.buf + prev_gprs; - fpr = (union fpr *)state->fprs.buf + prev_fprs; - args_shrink(&state->args, prev_argc); - DISPATCH(); + paramc = argc; + for (size_t i = 0; i < argc; ++i) + params[i] = args[i]; - DO(CALLI_F); - struct ejit_func *f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; + goto top; + DISPATCH(); - retval_f = ejit_run(f, argc, args, state, true, NULL).f; + DO(CALLR_I); + retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + argc = 0; + DISPATCH(); - gpr = state->gprs.buf + prev_gprs; - fpr = (union fpr *)state->fprs.buf + prev_fprs; - args_shrink(&state->args, prev_argc); + DO(CALLR_L); + retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + argc = 0; DISPATCH(); - DO(CALLI_D); - struct ejit_func *f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; + DO(CALLR_F); + retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + argc = 0; + DISPATCH(); - retval_f = ejit_run(f, argc, args, state, true, NULL).f; + DO(CALLR_D); + retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + argc = 0; + DISPATCH(); - gpr = state->gprs.buf + prev_gprs; - fpr = (union fpr *)state->fprs.buf + prev_fprs; - args_shrink(&state->args, prev_argc); + DO(CALLI); + retval = ejit_run((struct ejit_func *)i.p, argc, args, NULL); + argc = 0; DISPATCH(); DO(ESCAPEI_I); - ejit_escape_i_t f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; - - retval = f(argc, args); - - args_shrink(&state->args, prev_argc); + retval.i = ((ejit_escape_i_t)i.p)(argc, args); + argc = 0; DISPATCH(); DO(ESCAPEI_L); - ejit_escape_l_t f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; - - retval = f(argc, args); - - args_shrink(&state->args, prev_argc); + retval.i = ((ejit_escape_l_t)i.p)(argc, args); + argc = 0; DISPATCH(); DO(ESCAPEI_F); - ejit_escape_f_t f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; - - retval_f = f(argc, args); - - args_shrink(&state->args, prev_argc); + retval.f = ((ejit_escape_f_t)i.p)(argc, args); + argc = 0; DISPATCH(); DO(ESCAPEI_D); - ejit_escape_d_t f = i.p; - size_t argc = args_len(&state->args) - prev_argc; - struct ejit_arg *args = state->args.buf + prev_argc; - - retval_f = f(argc, args); - - args_shrink(&state->args, prev_argc); + retval.f = ((ejit_escape_d_t)i.p)(argc, args); + argc = 0; DISPATCH(); /* dispatch is technically unnecessary for returns, but keep it for * symmetry */ DO(RETR); - retval = gpr[i.r1]; - goto out_int; + return (union interp_ret){.i = gpr[i.r1]}; DISPATCH(); DO(RETI); - retval = i.o; - goto out_int; + return (union interp_ret){.i = i.o}; DISPATCH(); DO(RETR_F); - retval_f = fpr[i.r1].f; - goto out_float; + return (union interp_ret){.f = fpr[i.r1].f}; DISPATCH(); DO(RETR_D); - retval_f = fpr[i.r1].d; - goto out_float; + return (union interp_ret){.f = fpr[i.r1].d}; DISPATCH(); DO(RETI_F); - retval_f = i.f; - goto out_float; + return (union interp_ret){.f = i.f}; DISPATCH(); DO(RETI_D); - retval_f = i.d; - goto out_float; + return (union interp_ret){.f = i.d}; DISPATCH(); #undef DISPATCH #undef JUMP #undef DO -out_float: - gprs_shrink(&state->gprs, prev_gprs); - fprs_shrink(&state->fprs, prev_fprs); - return (union interp_ret){.f = retval_f}; - -out_int: - gprs_shrink(&state->gprs, prev_gprs); - fprs_shrink(&state->fprs, prev_fprs); - return (union interp_ret){.i = retval}; - -zero_out: return (union interp_ret){.i = 0}; } diff --git a/tests/calli.c b/tests/calli.c new file mode 100644 index 0000000..991e97d --- /dev/null +++ b/tests/calli.c @@ -0,0 +1,41 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +struct ejit_func *compile(bool do_jit) +{ + struct ejit_operand operands[2] = { + EJIT_OPERAND_GPR(0, EJIT_TYPE(long)), + EJIT_OPERAND_GPR(1, EJIT_TYPE(long)) + }; + struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands); + ejit_addr(f, EJIT_GPR(0), EJIT_GPR(0), EJIT_GPR(1)); + ejit_retr(f, EJIT_GPR(0)); + ejit_select_compile_func(f, 2, 0, EJIT_USE64(long), do_jit, true); + return f; +} + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_func *target = compile(do_jit); + + struct ejit_operand operands[2] = { + EJIT_OPERAND_GPR(0, EJIT_TYPE(long)), + EJIT_OPERAND_GPR(1, EJIT_TYPE(long)) + }; + + struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands); + ejit_calli(f, target, 2, operands); + ejit_retval(f, EJIT_GPR(0)); + ejit_retr(f, EJIT_GPR(0)); + ejit_select_compile_func(f, 2, 0, EJIT_USE64(long), do_jit, true); + + assert(erfi2(f, + EJIT_ARG(42, long), + EJIT_ARG(69, long)) == 111); + + ejit_destroy_func(target); + ejit_destroy_func(f); +} diff --git a/tests/callr_i.c b/tests/callr_i.c new file mode 100644 index 0000000..00b5374 --- /dev/null +++ b/tests/callr_i.c @@ -0,0 +1,42 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +struct ejit_func *compile(bool do_jit) +{ + struct ejit_operand operands[2] = { + EJIT_OPERAND_GPR(0, EJIT_TYPE(long)), + EJIT_OPERAND_GPR(1, EJIT_TYPE(long)) + }; + struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands); + ejit_addr(f, EJIT_GPR(0), EJIT_GPR(0), EJIT_GPR(1)); + ejit_retr(f, EJIT_GPR(0)); + ejit_select_compile_func(f, 2, 0, EJIT_USE64(long), do_jit, true); + return f; +} + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_func *target = compile(do_jit); + + struct ejit_operand operands[2] = { + EJIT_OPERAND_GPR(0, EJIT_TYPE(long)), + EJIT_OPERAND_GPR(1, EJIT_TYPE(long)) + }; + + struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands); + ejit_movi(f, EJIT_GPR(2), (uintptr_t)target); + ejit_callr_i(f, EJIT_GPR(2), 2, operands); + ejit_retval(f, EJIT_GPR(0)); + ejit_retr(f, EJIT_GPR(0)); + ejit_select_compile_func(f, 3, 0, EJIT_USE64(long), do_jit, true); + + assert(erfi2(f, + EJIT_ARG(42, long), + EJIT_ARG(69, long)) == 111); + + ejit_destroy_func(target); + ejit_destroy_func(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 new file mode 100644 index 0000000..5517c35 --- /dev/null +++ b/tests/escapei_immediate_10.c @@ -0,0 +1,63 @@ +#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); + 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); +} + +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); +} diff --git a/tests/makefile b/tests/makefile index 5aeef98..53115de 100644 --- a/tests/makefile +++ b/tests/makefile @@ -1,25 +1,35 @@ include ./tests.mk -LLVM ?= 0 -CROSS_COMPILE := -COMPILER != [ "$(LLVM)" != "0" ] \ - && echo clang --target="$(CROSS_COMPILE)" \ - || echo $(CROSS_COMPILE)gcc +LLVM ?= 0 +COMPILER != [ -n "$(CROSS_COMPILE)" ] \ + && { \ + [ "$(LLVM)" != "0" ] \ + && echo clang --target="$(CROSS_COMPILE)" \ + || echo $(CROSS_COMPILE)gcc \ + ; \ + } \ + || echo $(CC) -CFLAGS := -Wall -Wextra -O0 -g +RELEASE ?= 0 +OPTFLAGS != [ "$(RELEASE)" != "0" ] \ + && echo "-O2" \ + || echo "-O0" + +LTO ?= 0 +LTOFLAGS != [ "$(LTO)" != "0" ] \ + && echo "-flto=auto" + +DEBUG ?= 1 +DEBUGFLAGS != [ "$(DEBUG)" != "0" ] \ + && echo "-DDEBUG=1" \ + || echo "-DNDEBUG=1" + +OBFLAGS := -g +WARNFLAGS := -Wall -Wextra INCLUDE_FLAGS := -I include -COMPILE_TEST := $(COMPILER) $(CFLAGS) $(INCLUDE_FLAGS) +COMPILE_TEST := $(COMPILER) $(WARNFLAGS) $(OPTFLAGS) $(LTOFLAGS) \ + $(OBFLAGS) $(CFLAGS) $(DEBUGFLAGS) $(INCLUDE_FLAGS) .PHONY: check check: $(TESTS) - @echo "Running bytecode tests..." - @set -e; for test in $(TESTS); do \ - echo "Testing: $$test"; \ - ./$$test; \ - done - @echo "Running jit tests..." - @set -e; for test in $(TESTS); do \ - echo "Testing: $$test"; \ - ./$$test 1; \ - done @echo "Success!" diff --git a/tests/maxr_d.c b/tests/maxr_d.c new file mode 100644 index 0000000..3e35665 --- /dev/null +++ b/tests/maxr_d.c @@ -0,0 +1,28 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[2] = { + EJIT_OPERAND_FPR(0, EJIT_TYPE(double)), + EJIT_OPERAND_FPR(1, EJIT_TYPE(double)) + }; + + struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands); + + ejit_maxr_d(f, EJIT_FPR(2), EJIT_FPR(0), EJIT_FPR(1)); + ejit_retr_d(f, EJIT_FPR(2)); + + ejit_select_compile_func(f, 0, 3, EJIT_USE64(double), do_jit, true); + + assert(erfd2(f, EJIT_ARG(42., double), EJIT_ARG(69., double) + ) == 69.); + + assert(erfd2(f, EJIT_ARG(-42., double), EJIT_ARG(-69., double) + ) == -42.); + + ejit_destroy_func(f); +} diff --git a/tests/maxr_f.c b/tests/maxr_f.c new file mode 100644 index 0000000..581f867 --- /dev/null +++ b/tests/maxr_f.c @@ -0,0 +1,28 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[2] = { + EJIT_OPERAND_FPR(0, EJIT_TYPE(float)), + EJIT_OPERAND_FPR(1, EJIT_TYPE(float)) + }; + + struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 2, operands); + + ejit_maxr_f(f, EJIT_FPR(2), EJIT_FPR(0), EJIT_FPR(1)); + ejit_retr_f(f, EJIT_FPR(2)); + + ejit_select_compile_func(f, 0, 3, EJIT_USE64(float), do_jit, true); + + assert(erff2(f, EJIT_ARG(42., float), EJIT_ARG(69., float) + ) == 69.); + + assert(erff2(f, EJIT_ARG(-42., float), EJIT_ARG(-69., float) + ) == -42.); + + ejit_destroy_func(f); +} diff --git a/tests/minr_d.c b/tests/minr_d.c new file mode 100644 index 0000000..d0fb7c8 --- /dev/null +++ b/tests/minr_d.c @@ -0,0 +1,28 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[2] = { + EJIT_OPERAND_FPR(0, EJIT_TYPE(double)), + EJIT_OPERAND_FPR(1, EJIT_TYPE(double)) + }; + + struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands); + + ejit_minr_d(f, EJIT_FPR(2), EJIT_FPR(0), EJIT_FPR(1)); + ejit_retr_d(f, EJIT_FPR(2)); + + ejit_select_compile_func(f, 0, 3, EJIT_USE64(double), do_jit, true); + + assert(erfd2(f, EJIT_ARG(42., double), EJIT_ARG(69., double) + ) == 42.); + + assert(erfd2(f, EJIT_ARG(-42., double), EJIT_ARG(-69., double) + ) == -69.); + + ejit_destroy_func(f); +} diff --git a/tests/minr_f.c b/tests/minr_f.c new file mode 100644 index 0000000..b02ec06 --- /dev/null +++ b/tests/minr_f.c @@ -0,0 +1,28 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[2] = { + EJIT_OPERAND_FPR(0, EJIT_TYPE(float)), + EJIT_OPERAND_FPR(1, EJIT_TYPE(float)) + }; + + struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 2, operands); + + ejit_minr_f(f, EJIT_FPR(2), EJIT_FPR(0), EJIT_FPR(1)); + ejit_retr_f(f, EJIT_FPR(2)); + + ejit_select_compile_func(f, 0, 3, EJIT_USE64(float), do_jit, true); + + assert(erff2(f, EJIT_ARG(42., float), EJIT_ARG(69., float) + ) == 42.); + + assert(erff2(f, EJIT_ARG(-42., float), EJIT_ARG(-69., float) + ) == -69.); + + ejit_destroy_func(f); +} diff --git a/tests/sqrtr_d.c b/tests/sqrtr_d.c new file mode 100644 index 0000000..06e7894 --- /dev/null +++ b/tests/sqrtr_d.c @@ -0,0 +1,23 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[1] = { + EJIT_OPERAND_FPR(0, EJIT_TYPE(double)), + }; + struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands); + + ejit_sqrtr_d(f, EJIT_FPR(0), EJIT_FPR(0)); + ejit_retr_d(f, EJIT_FPR(0)); + + ejit_select_compile_func(f, 0, 1, EJIT_USE64(double), do_jit, true); + + assert(erfd1(f, EJIT_ARG( 0.0, double)) == 0.0); + assert(erfd1(f, EJIT_ARG( 4.0, double)) == 2.0); + assert(erfd1(f, EJIT_ARG(-4.0, double)) + != erfd1(f, EJIT_ARG(-4.0, double))); // nan +} diff --git a/tests/sqrtr_f.c b/tests/sqrtr_f.c new file mode 100644 index 0000000..3baa00d --- /dev/null +++ b/tests/sqrtr_f.c @@ -0,0 +1,23 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[1] = { + EJIT_OPERAND_FPR(0, EJIT_TYPE(float)), + }; + struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 1, operands); + + ejit_sqrtr_f(f, EJIT_FPR(0), EJIT_FPR(0)); + ejit_retr_f(f, EJIT_FPR(0)); + + ejit_select_compile_func(f, 0, 1, EJIT_USE64(float), do_jit, true); + + assert(erff1(f, EJIT_ARG( 0.0, float)) == 0.0); + assert(erff1(f, EJIT_ARG( 4.0, float)) == 2.0); + assert(erff1(f, EJIT_ARG(-4.0, float)) + != erff1(f, EJIT_ARG(-4.0, float))); // nan +} diff --git a/tests/taili.c b/tests/taili.c new file mode 100644 index 0000000..cc09f59 --- /dev/null +++ b/tests/taili.c @@ -0,0 +1,39 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[2] = { + EJIT_OPERAND_GPR(0, EJIT_INT32), /* s */ + EJIT_OPERAND_GPR(1, EJIT_INT32) /* n */ + }; + + struct ejit_func *f = ejit_create_func(EJIT_INT32, 2, operands); + + /* n == 0, return s */ + struct ejit_reloc r = ejit_bnei(f, EJIT_GPR(1), 0); + ejit_retr(f, EJIT_GPR(0)); + ejit_patch(f, r, ejit_label(f)); + + /* s += n */ + ejit_addr(f, EJIT_GPR(0), EJIT_GPR(0), EJIT_GPR(1)); + + /* n -= 1 */ + ejit_subi(f, EJIT_GPR(1), EJIT_GPR(1), 1); + + struct ejit_operand args[2] = { + EJIT_OPERAND_GPR(0, EJIT_INT32), /* s */ + EJIT_OPERAND_GPR(1, EJIT_INT32) /* n */ + }; + ejit_taili(f, f, 2, args); + + ejit_select_compile_func(f, 2, 0, EJIT_USE64(uintptr_t), do_jit, true); + + /* arbitrary number but large enough to most likely cause a stack fault + * if the tail call leaks memory or something */ + assert((int32_t)erfi2(f, EJIT_ARG(0, int32_t), EJIT_ARG(1000000, int32_t)) == 1784293664); + ejit_destroy_func(f); +} diff --git a/tests/tailr.c b/tests/tailr.c new file mode 100644 index 0000000..69ad44b --- /dev/null +++ b/tests/tailr.c @@ -0,0 +1,41 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_operand operands[2] = { + EJIT_OPERAND_GPR(0, EJIT_INT32), /* s */ + EJIT_OPERAND_GPR(1, EJIT_INT32) /* n */ + }; + + struct ejit_func *f = ejit_create_func(EJIT_INT32, 2, operands); + + /* n == 0, return s */ + struct ejit_reloc r = ejit_bnei(f, EJIT_GPR(1), 0); + ejit_retr(f, EJIT_GPR(0)); + ejit_patch(f, r, ejit_label(f)); + + /* s += n */ + ejit_addr(f, EJIT_GPR(0), EJIT_GPR(0), EJIT_GPR(1)); + + /* n -= 1 */ + ejit_subi(f, EJIT_GPR(1), EJIT_GPR(1), 1); + + struct ejit_operand args[2] = { + EJIT_OPERAND_GPR(0, EJIT_INT32), /* s */ + EJIT_OPERAND_GPR(1, EJIT_INT32) /* n */ + }; + + ejit_movi(f, EJIT_GPR(2), (uintptr_t)f); + ejit_tailr(f, EJIT_GPR(2), 2, args); + + ejit_select_compile_func(f, 3, 0, EJIT_USE64(uintptr_t), do_jit, true); + + /* arbitrary number but large enough to most likely cause a stack fault + * if the tail call leaks memory or something */ + assert((int32_t)erfi2(f, EJIT_ARG(0, int32_t), EJIT_ARG(1000000, int32_t)) == 1784293664); + ejit_destroy_func(f); +} |