From 0986ae8a862028e0acc95795de13254fe1559638 Mon Sep 17 00:00:00 2001 From: pcpa Date: Thu, 30 Apr 2015 17:40:14 -0300 Subject: [PATCH] aarch64: Add initial jit_va_ calls to aarch64 * lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c, lib/jit_aarch64.c: Add base support to jit vararg functions to the aarch64 backend. --- ChangeLog | 6 +++ lib/jit_aarch64-cpu.c | 112 ++++++++++++++++++++++++++++++++++++++++++ lib/jit_aarch64-fpu.c | 55 +++++++++++++++++++++ lib/jit_aarch64.c | 65 ++++++++++++++++++++++++ 4 files changed, 238 insertions(+) diff --git a/ChangeLog b/ChangeLog index 035468548..7ace2c57b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-05-30 Paulo Andrade + + * lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c, + lib/jit_aarch64.c: Add base support to jit vararg + functions to the aarch64 backend. + 2015-05-27 Paulo Andrade * include/lightning.h, include/lightning/jit_private.h, diff --git a/lib/jit_aarch64-cpu.c b/lib/jit_aarch64-cpu.c index 2363d28c1..4b1562932 100644 --- a/lib/jit_aarch64-cpu.c +++ b/lib/jit_aarch64-cpu.c @@ -212,6 +212,8 @@ typedef union { } instr_t; # define stack_framesize 160 # define ii(i) *_jit->pc.ui++ = i +# define ldr(r0,r1) ldr_l(r0,r1) +# define ldxr(r0,r1,r2) ldxr_l(r0,r1,r2) # define ldxi(r0,r1,i0) ldxi_l(r0,r1,i0) # define stxi(i0,r0,r1) stxi_l(i0,r0,r1) # define FP_REGNO 0x1d @@ -782,6 +784,10 @@ static jit_word_t _calli_p(jit_state_t*,jit_word_t); static void _prolog(jit_state_t*,jit_node_t*); # define epilog(i0) _epilog(_jit,i0) static void _epilog(jit_state_t*,jit_node_t*); +# define vastart(r0) _vastart(_jit, r0) +static void _vastart(jit_state_t*, jit_int32_t); +# define vaarg(r0, r1) _vaarg(_jit, r0, r1) +static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t); # define patch_at(jump,label) _patch_at(_jit,jump,label) static void _patch_at(jit_state_t*,jit_word_t,jit_word_t); #endif @@ -2241,6 +2247,24 @@ _prolog(jit_state_t *_jit, jit_node_t *node) stxi_i(_jitc->function->aoffoff, FP_REGNO, rn(reg)); jit_unget_reg(reg); } + + if (_jitc->function->self.call & jit_call_varargs) { + /* Save gp registers in the save area, if any is a vararg */ + for (reg = 8 - _jitc->function->vagp / -8; + jit_arg_reg_p(reg); ++reg) + stxi(_jitc->function->vaoff + offsetof(jit_va_list_t, x0) + + reg * 8, FP_REGNO, rn(JIT_RA0 - reg)); + + for (reg = 8 - _jitc->function->vafp / -16; + jit_arg_f_reg_p(reg); ++reg) + /* Save fp registers in the save area, if any is a vararg */ + /* Note that the full 16 byte register is not saved, because + * lightning only handles float and double, and, while + * attempting to provide a va_list compatible pointer as + * jit_va_start return, does not guarantee it (on all ports). */ + stxi_d(_jitc->function->vaoff + offsetof(jit_va_list_t, q0) + + reg * 16 + offsetof(jit_qreg_t, l), FP_REGNO, rn(_V0 - reg)); + } } static void @@ -2285,6 +2309,94 @@ _epilog(jit_state_t *_jit, jit_node_t *node) RET(); } +static void +_vastart(jit_state_t *_jit, jit_int32_t r0) +{ + jit_int32_t reg; + + assert(_jitc->function->self.call & jit_call_varargs); + + /* Return jit_va_list_t in the register argument */ + addi(r0, FP_REGNO, _jitc->function->vaoff); + + reg = jit_get_reg(jit_class_gpr); + + /* Initialize stack pointer to the first stack argument. */ + addi(rn(reg), FP_REGNO, _jitc->function->self.size); + stxi(offsetof(jit_va_list_t, stack), r0, rn(reg)); + + /* Initialize gp top pointer to the first stack argument. */ + addi(rn(reg), r0, va_gp_top_offset); + stxi(offsetof(jit_va_list_t, gptop), r0, rn(reg)); + + /* Initialize fp top pointer to the first stack argument. */ + addi(rn(reg), r0, va_fp_top_offset); + stxi(offsetof(jit_va_list_t, fptop), r0, rn(reg)); + + /* Initialize gp offset in the save area. */ + movi(rn(reg), _jitc->function->vagp); + stxi_i(offsetof(jit_va_list_t, gpoff), r0, rn(reg)); + + /* Initialize fp offset in the save area. */ + movi(rn(reg), _jitc->function->vafp); + stxi_i(offsetof(jit_va_list_t, fpoff), r0, rn(reg)); + + jit_unget_reg(reg); +} + +static void +_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1) +{ + jit_word_t ge_code; + jit_word_t lt_code; + jit_int32_t rg0, rg1; + + assert(_jitc->function->self.call & jit_call_varargs); + + rg0 = jit_get_reg(jit_class_gpr); + rg1 = jit_get_reg(jit_class_gpr); + + /* Load the gp offset in save area in the first temporary. */ + ldxi_i(rn(rg0), r1, offsetof(jit_va_list_t, gpoff)); + + /* Jump over if there are no remaining arguments in the save area. */ + ge_code = bgei(_jit->pc.w, rn(rg0), 0); + + /* Load the gp save pointer in the second temporary. */ + ldxi(rn(rg1), r1, offsetof(jit_va_list_t, gptop)); + + /* Load the vararg argument in the first argument. */ + ldxr(r0, rn(rg1), rn(rg0)); + + /* Update the gp offset. */ + addi(rn(rg0), rn(rg0), 8); + stxi_i(offsetof(jit_va_list_t, gpoff), r1, rn(rg0)); + + /* Will only need one temporary register below. */ + jit_unget_reg(rg1); + + /* Jump over overflow code. */ + lt_code = jmpi_p(_jit->pc.w); + + /* Where to land if argument is in overflow area. */ + patch_at(ge_code, _jit->pc.w); + + /* Load stack pointer. */ + ldxi(rn(rg0), r1, offsetof(jit_va_list_t, stack)); + + /* Load argument. */ + ldr(r0, rn(rg0)); + + /* Update stack pointer. */ + addi(rn(rg0), rn(rg0), 8); + stxi(offsetof(jit_va_list_t, stack), r1, rn(rg0)); + + /* Where to land if argument is in gp save area. */ + patch_at(lt_code, _jit->pc.w); + + jit_unget_reg(rg0); +} + static void _patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label) { diff --git a/lib/jit_aarch64-fpu.c b/lib/jit_aarch64-fpu.c index 386f068e2..1f13a14f1 100644 --- a/lib/jit_aarch64-fpu.c +++ b/lib/jit_aarch64-fpu.c @@ -310,6 +310,8 @@ static jit_word_t _bltgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t); # define bordi_d(i0,r0,i1) dbcci(BCC_VC,i0,r0,i1) # define bunordr_d(i0,r0,r1) dbccr(BCC_VS,i0,r0,r1) # define bunordi_d(i0,r0,i1) dbcci(BCC_VS,i0,r0,i1) +# define vaarg_d(r0, r1) _vaarg_d(_jit, r0, r1) +static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t); #endif #if CODE @@ -856,4 +858,57 @@ _bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1) return (w); } dbopi(ltgt) + +static void +_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1) +{ + jit_word_t ge_code; + jit_word_t lt_code; + jit_int32_t rg0, rg1; + + assert(_jitc->function->self.call & jit_call_varargs); + + rg0 = jit_get_reg(jit_class_gpr); + rg1 = jit_get_reg(jit_class_gpr); + + /* Load the fp offset in save area in the first temporary. */ + ldxi_i(rn(rg0), r1, offsetof(jit_va_list_t, fpoff)); + + /* Jump over if there are no remaining arguments in the save area. */ + ge_code = bgei(_jit->pc.w, rn(rg0), 0); + + /* Load the gp save pointer in the second temporary. */ + ldxi(rn(rg1), r1, offsetof(jit_va_list_t, fptop)); + + /* Load the vararg argument in the first argument. */ + ldxr_d(r0, rn(rg1), rn(rg0)); + + /* Update the fp offset. */ + addi(rn(rg0), rn(rg0), 16); + stxi_i(offsetof(jit_va_list_t, fpoff), r1, rn(rg0)); + + /* Will only need one temporary register below. */ + jit_unget_reg(rg1); + + /* Jump over overflow code. */ + lt_code = jmpi_p(_jit->pc.w); + + /* Where to land if argument is in overflow area. */ + patch_at(ge_code, _jit->pc.w); + + /* Load stack pointer. */ + ldxi(rn(rg0), r1, offsetof(jit_va_list_t, stack)); + + /* Load argument. */ + ldr(r0, rn(rg0)); + + /* Update stack pointer. */ + addi(rn(rg0), rn(rg0), 8); + stxi(offsetof(jit_va_list_t, stack), r1, rn(rg0)); + + /* Where to land if argument is in gp save area. */ + patch_at(lt_code, _jit->pc.w); + + jit_unget_reg(rg0); +} #endif diff --git a/lib/jit_aarch64.c b/lib/jit_aarch64.c index 77256c958..89c3edad6 100644 --- a/lib/jit_aarch64.c +++ b/lib/jit_aarch64.c @@ -22,6 +22,41 @@ #define jit_arg_reg_p(i) ((i) >= 0 && (i) < 8) #define jit_arg_f_reg_p(i) ((i) >= 0 && (i) < 8) +typedef struct jit_qreg { + jit_float64_t l; + jit_float64_t h; +} jit_qreg_t; + +#define va_gp_min_offset -64 +#define va_gp_top_offset offsetof(jit_va_list_t, q0) +#define va_fp_min_offset -128 +#define va_fp_top_offset sizeof(jit_va_list_t) +typedef struct jit_va_list { + jit_pointer_t stack; + jit_pointer_t gptop; + jit_pointer_t fptop; + jit_int32_t gpoff; + jit_int32_t fpoff; + + jit_int64_t x0; + jit_int64_t x1; + jit_int64_t x2; + jit_int64_t x3; + jit_int64_t x4; + jit_int64_t x5; + jit_int64_t x6; + jit_int64_t x7; + + jit_qreg_t q0; + jit_qreg_t q1; + jit_qreg_t q2; + jit_qreg_t q3; + jit_qreg_t q4; + jit_qreg_t q5; + jit_qreg_t q6; + jit_qreg_t q7; +} jit_va_list_t; + /* * Prototypes */ @@ -295,6 +330,23 @@ _jit_ellipsis(jit_state_t *_jit) else { assert(!(_jitc->function->self.call & jit_call_varargs)); _jitc->function->self.call |= jit_call_varargs; + + /* Allocate va_list like object in the stack, + * with enough space to save all argument + * registers, and use fixed offsets for them. */ + _jitc->function->vaoff = jit_allocai(sizeof(jit_va_list_t)); + + /* Initialize gp offset in save area. */ + if (jit_arg_reg_p(_jitc->function->self.argi)) + _jitc->function->vagp = (8 - _jitc->function->self.argi) * -8; + else + _jitc->function->vagp = va_gp_min_offset; + + /* Initialize fp offset in save area. */ + if (jit_arg_f_reg_p(_jitc->function->self.argf)) + _jitc->function->vafp = (8 - _jitc->function->self.argf) * -16; + else + _jitc->function->vafp = va_fp_min_offset; } } @@ -303,6 +355,7 @@ _jit_arg(jit_state_t *_jit) { jit_int32_t offset; assert(_jitc->function); + assert(!(_jitc->function->self.call & jit_call_varargs)); if (jit_arg_reg_p(_jitc->function->self.argi)) offset = _jitc->function->self.argi++; else { @@ -317,6 +370,7 @@ _jit_arg_f(jit_state_t *_jit) { jit_int32_t offset; assert(_jitc->function); + assert(!(_jitc->function->self.call & jit_call_varargs)); if (jit_arg_f_reg_p(_jitc->function->self.argf)) offset = _jitc->function->self.argf++; else { @@ -331,6 +385,7 @@ _jit_arg_d(jit_state_t *_jit) { jit_int32_t offset; assert(_jitc->function); + assert(!(_jitc->function->self.call & jit_call_varargs)); if (jit_arg_f_reg_p(_jitc->function->self.argf)) offset = _jitc->function->self.argf++; else { @@ -1268,9 +1323,19 @@ _emit_code(jit_state_t *_jit) epilog(node); _jitc->function = NULL; break; + case jit_code_va_start: + vastart(rn(node->u.w)); + break; + case jit_code_va_arg: + vaarg(rn(node->u.w), rn(node->v.w)); + break; + case jit_code_va_arg_d: + vaarg_d(rn(node->u.w), rn(node->v.w)); + break; case jit_code_live: case jit_code_arg: case jit_code_arg_f: case jit_code_arg_d: + case jit_code_va_end: break; default: abort();