diff --git a/ChangeLog b/ChangeLog index 7ace2c57b..dcd359829 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-06-01 Paulo Andrade + + * lib/jit_arm-cpu.c, lib/jit_arm-swf.c, lib/jit_arm-vfp.c, + lib/jit_arm.c: Add base support to jit vararg + functions to the arm backend. + 2015-05-30 Paulo Andrade * lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c, diff --git a/lib/jit_arm-cpu.c b/lib/jit_arm-cpu.c index 3c4d8524e..07b4630dd 100644 --- a/lib/jit_arm-cpu.c +++ b/lib/jit_arm-cpu.c @@ -18,6 +18,9 @@ */ #if PROTO +# define stxi(i0,r0,r1) stxi_i(i0,r0,r1) +# define ldxi(r0,r1,i0) ldxi_i(r0,r1,i0) +# define ldr(r0,r1) ldr_i(r0,r1) # define _s20P(d) ((d) >= -(int)0x80000 && d <= 0x7ffff) # define _s24P(d) ((d) >= -(int)0x800000 && d <= 0x7fffff) # define _u3(v) ((v) & 0x7) @@ -1115,6 +1118,10 @@ static void _callr(jit_state_t*,jit_int32_t); static void _calli(jit_state_t*,jit_word_t); # define calli_p(i0) _calli_p(_jit,i0) static jit_word_t _calli_p(jit_state_t*,jit_word_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(kind,jump,label) _patch_at(_jit,kind,jump,label) static void _patch_at(jit_state_t*,jit_int32_t,jit_word_t,jit_word_t); #endif @@ -3771,22 +3778,43 @@ _prolog(jit_state_t *_jit, jit_node_t *node) BX(_R12_REGNO); if (!_jitc->thumb) _jitc->thumb = _jit->pc.w; + + /* If the jit function is varargs, do a slightly more + * costly prolog to save first the 4 argument registers. */ if (jit_cpu.abi) { + if (_jitc->function->self.call & jit_call_varargs) + T2_PUSH(0xf); T2_PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO)); VPUSH_F64(_D8_REGNO, 8); - T2_PUSH(0xf); + if (!(_jitc->function->self.call & jit_call_varargs)) + T2_PUSH(0xf); + } + else { + if (_jitc->function->self.call & jit_call_varargs) { + T2_PUSH(0xf); + T2_PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO)); + } + else + T2_PUSH(0x3ff|(1<<_FP_REGNO)|(1<<_LR_REGNO)); } - else - T2_PUSH(0x3ff|(1<<_FP_REGNO)|(1<<_LR_REGNO)); } else { if (jit_cpu.abi) { + if (_jitc->function->self.call & jit_call_varargs) + PUSH(0xf); PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO)); VPUSH_F64(_D8_REGNO, 8); - PUSH(0xf); + if (!(_jitc->function->self.call & jit_call_varargs)) + PUSH(0xf); + } + else { + if (_jitc->function->self.call & jit_call_varargs) { + PUSH(0xf); + PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO)); + } + else + PUSH(0x3ff|(1<<_FP_REGNO)|(1<<_LR_REGNO)); } - else - PUSH(0x3ff|(1<<_FP_REGNO)|(1<<_LR_REGNO)); } movr(_FP_REGNO, _SP_REGNO); if (_jitc->function->stack) @@ -3804,17 +3832,84 @@ _epilog(jit_state_t *_jit, jit_node_t *node) { if (_jitc->function->assume_frame) return; - addi(_SP_REGNO, _FP_REGNO, 16); + + /* If the jit function is varargs, need a different + * epilog, that also does not directly restore the + * pc, but instead branch to the lr, after correcting + * the stack. */ + if (_jitc->function->self.call & jit_call_varargs) + movr(_SP_REGNO, _FP_REGNO); + else + addi(_SP_REGNO, _FP_REGNO, 16); if (jit_cpu.abi) VPOP_F64(_D8_REGNO, 8); - if (jit_thumb_p()) - T2_POP(0x3f0|(1<<_FP_REGNO)|(1<<_PC_REGNO)); - else - POP(0x3f0|(1<<_FP_REGNO)|(1<<_PC_REGNO)); + if (jit_thumb_p()) { + if (!(_jitc->function->self.call & jit_call_varargs)) + T2_POP(0x3f0|(1<<_FP_REGNO)|(1<<_PC_REGNO)); + else + T2_POP(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO)); + } + else { + if (!(_jitc->function->self.call & jit_call_varargs)) + POP(0x3f0|(1<<_FP_REGNO)|(1<<_PC_REGNO)); + else + POP(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO)); + } + if (_jitc->function->self.call & jit_call_varargs) { + addi(_SP_REGNO, _SP_REGNO, 16); + if (jit_thumb_p()) + T1_BX(_LR_REGNO); + else + BX(_LR_REGNO); + } if (jit_thumb_p() && (_jit->pc.w & 2)) T1_NOP(); } +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. + * The -16 is to account for the 4 argument registers + * always saved, and _jitc->function->vagp is to account + * for declared arguments. */ + addi(rn(reg), _FP_REGNO, _jitc->function->self.size - + 16 + _jitc->function->vagp); + stxi(offsetof(jit_va_list_t, stack), r0, rn(reg)); + + jit_unget_reg(reg); +} + +static void +_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1) +{ + jit_int32_t reg; + + assert(_jitc->function->self.call & jit_call_varargs); + + reg = jit_get_reg(jit_class_gpr); + + /* Load stack pointer. */ + ldxi(rn(reg), r1, offsetof(jit_va_list_t, stack)); + + /* Load argument. */ + ldr(r0, rn(reg)); + + /* Update stack pointer. */ + addi(rn(reg), rn(reg), sizeof(jit_word_t)); + stxi(offsetof(jit_va_list_t, stack), r1, rn(reg)); + + jit_unget_reg(reg); +} + static void _patch_at(jit_state_t *_jit, jit_int32_t kind, jit_word_t instr, jit_word_t label) diff --git a/lib/jit_arm-swf.c b/lib/jit_arm-swf.c index 8ba2b799e..6e041fc83 100644 --- a/lib/jit_arm-swf.c +++ b/lib/jit_arm-swf.c @@ -322,6 +322,8 @@ static void _swf_stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t); static void _swf_stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t); # define swf_stxi_d(r0,r1,i0) _swf_stxi_d(_jit,r0,r1,i0) static void _swf_stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t); +# define swf_vaarg_d(r0, r1) _swf_vaarg_d(_jit, r0, r1) +static void _swf_vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t); #endif #if CODE @@ -2614,4 +2616,31 @@ _swf_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1) } } } + +static void +_swf_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1) +{ + jit_int32_t rg0, rg1; + + assert(_jitc->function->self.call & jit_call_varargs); + + rg0 = jit_get_reg(jit_class_gpr); + + /* Load stack pointer. */ + ldxi(rn(rg0), r1, offsetof(jit_va_list_t, stack)); + rg1 = jit_get_reg(jit_class_gpr); + andi(rn(rg1), rn(rg0), 7); + addr(rn(rg0), rn(rg0), rn(rg1)); + jit_unget_reg(rg1); + + /* Load argument. */ + swf_ldr_d(r0, rn(rg0)); + + /* Update stack pointer. */ + addi(rn(rg0), rn(rg0), sizeof(jit_float64_t)); + stxi(offsetof(jit_va_list_t, stack), r1, rn(rg0)); + + jit_unget_reg(rg0); +} + #endif diff --git a/lib/jit_arm-vfp.c b/lib/jit_arm-vfp.c index 59e905f9b..69669428f 100644 --- a/lib/jit_arm-vfp.c +++ b/lib/jit_arm-vfp.c @@ -804,6 +804,8 @@ static void _vfp_stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t); static void _vfp_stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t); # define vfp_stxi_d(i0,r0,r1) _vfp_stxi_d(_jit,i0,r0,r1) static void _vfp_stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t); +# define vfp_vaarg_d(r0, r1) _vfp_vaarg_d(_jit, r0, r1) +static void _vfp_vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t); #endif #if CODE @@ -2301,6 +2303,32 @@ _vfp_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1) jit_unget_reg(reg); } } + +static void +_vfp_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1) +{ + jit_int32_t rg0, rg1; + + assert(_jitc->function->self.call & jit_call_varargs); + + rg0 = jit_get_reg(jit_class_gpr); + + /* Load stack pointer. */ + ldxi(rn(rg0), r1, offsetof(jit_va_list_t, stack)); + rg1 = jit_get_reg(jit_class_gpr); + andi(rn(rg1), rn(rg0), 7); + addr(rn(rg0), rn(rg0), rn(rg1)); + jit_unget_reg(rg1); + + /* Load argument. */ + vfp_ldr_d(r0, rn(rg0)); + + /* Update stack pointer. */ + addi(rn(rg0), rn(rg0), sizeof(jit_float64_t)); + stxi(offsetof(jit_va_list_t, stack), r1, rn(rg0)); + + jit_unget_reg(rg0); +} # undef dbopi # undef fbopi # undef dopi diff --git a/lib/jit_arm.c b/lib/jit_arm.c index 6b3b3a3de..66ce126da 100644 --- a/lib/jit_arm.c +++ b/lib/jit_arm.c @@ -51,6 +51,10 @@ typedef union _jit_thumb_t { jit_int16_t s[2]; } jit_thumb_t; +typedef struct jit_va_list { + jit_pointer_t stack; +} jit_va_list_t; + /* * Prototypes */ @@ -415,6 +419,15 @@ _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. */ + _jitc->function->vaoff = jit_allocai(sizeof(jit_va_list_t)); + + /* First 4 stack addresses are always spilled r0-r3 */ + if (jit_arg_reg_p(_jitc->function->self.argi)) + _jitc->function->vagp = _jitc->function->self.argi * 4; + else + _jitc->function->vagp = 16; } } @@ -1703,9 +1716,22 @@ _emit_code(jit_state_t *_jit) else vfp_movi_d(rn(node->u.w), node->w.d); 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: + if (jit_swf_p()) + swf_vaarg_d(rn(node->u.w), rn(node->v.w)); + else + vfp_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();