diff --git a/jit/x86-cpu.c b/jit/x86-cpu.c index 7d5a1b79a..4bc5e3874 100644 --- a/jit/x86-cpu.c +++ b/jit/x86-cpu.c @@ -2638,18 +2638,19 @@ callr(jit_state_t *_jit, int32_t r0) static void calli(jit_state_t *_jit, jit_word_t i0) { - if (__X64) + ptrdiff_t rel32 = i0 - (_jit->pc.w + 4); + if (INT32_MIN <= rel32 && rel32 <= INT32_MAX) + { + ic(_jit, 0xe8); + ii(_jit, rel32); + } + else { int32_t reg = get_temp_gpr(_jit); jit_patch_there(_jit, mov_addr(_jit, rn(reg)), (void*)i0); callr(_jit, rn(reg)); unget_temp_gpr(_jit); } - else - { - ic(_jit, 0xe8); - ii(_jit, i0 - (_jit->pc.w + 4)); - } } static void @@ -2663,10 +2664,19 @@ jmpr(jit_state_t *_jit, int32_t r0) static void jmpi(jit_state_t *_jit, jit_word_t i0) { - jit_word_t w; - ic(_jit, 0xe9); - w = i0 - (_jit->pc.w + 4); - ii(_jit, w); + ptrdiff_t rel32 = i0 - (_jit->pc.w + 4); + if (INT32_MIN <= rel32 && rel32 <= INT32_MAX) + { + ic(_jit, 0xe9); + ii(_jit, rel32); + } + else + { + int32_t reg = get_temp_gpr(_jit); + jit_patch_there(_jit, mov_addr(_jit, rn(reg)), (void*)i0); + jmpr(_jit, rn(reg)); + unget_temp_gpr(_jit); + } } static jit_reloc_t diff --git a/tests/jmpi.c b/tests/jmpi.c new file mode 100644 index 000000000..2f9213fec --- /dev/null +++ b/tests/jmpi.c @@ -0,0 +1,21 @@ +#include "test.h" + +static int tail(void) { return 42; } + +static void +run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size) +{ + jit_begin(j, arena_base, arena_size); + + jit_jmpi(j, tail); + + int (*f)(void) = jit_end(j, NULL); + + ASSERT(f() == 42); +} + +int +main (int argc, char *argv[]) +{ + return main_helper(argc, argv, run_test); +} diff --git a/tests/jmpr.c b/tests/jmpr.c new file mode 100644 index 000000000..32a771791 --- /dev/null +++ b/tests/jmpr.c @@ -0,0 +1,27 @@ +#include "test.h" + +static int tail(void) { return 42; } + +static void +run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size) +{ + jit_begin(j, arena_base, arena_size); + + const jit_arg_abi_t abi[] = { JIT_ARG_ABI_POINTER }; + jit_arg_t args[1]; + const jit_anyreg_t regs[] = { { .gpr=JIT_R0 } }; + + jit_receive(j, 1, abi, args); + jit_load_args(j, 1, abi, args, regs); + + jit_jmpr(j, JIT_R0); + + int (*f)(void*) = jit_end(j, NULL); + ASSERT(f(tail) == 42); +} + +int +main (int argc, char *argv[]) +{ + return main_helper(argc, argv, run_test); +} diff --git a/tests/nop.c b/tests/nop.c new file mode 100644 index 000000000..16c5c8a7e --- /dev/null +++ b/tests/nop.c @@ -0,0 +1,24 @@ +#include "test.h" + +static void +run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size) +{ + jit_begin(j, arena_base, arena_size); + + size_t total = 0; + char *start = jit_address(j); + for (size_t i = 1; i < 10; total += i, i++) + jit_nop(j, i); + char *end = jit_address(j); + ASSERT(end - start == total); + jit_reti(j, 42); + + intmax_t (*f)(void) = jit_end(j, NULL); + ASSERT(f() == 42); +} + +int +main (int argc, char *argv[]) +{ + return main_helper(argc, argv, run_test); +}