diff --git a/ChangeLog b/ChangeLog index f6aa2bea6..bfd50a657 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-06-20 Paulo Andrade + + * lib/jit_alpha-cpu.c, lib/jit_alpha-fpu.c, lib/jit_alpha.c: + Add base support to jit vararg functions to the alpha backend. + 2015-06-19 Paulo Andrade * lib/jit_hppa-cpu.c, lib/jit_hppa-fpu.c, lib/jit_hppa.c: diff --git a/lib/jit_alpha-cpu.c b/lib/jit_alpha-cpu.c index 37ebfe2ac..ca9c9c380 100644 --- a/lib/jit_alpha-cpu.c +++ b/lib/jit_alpha-cpu.c @@ -52,7 +52,7 @@ # define _s32_p(v) ((v) >= -0x80000000 && (v) <= 0x7fffffff) # define _u32_p(v) ((v) >= 0 && (v) <= 0xffffffff) # define ii(i) *_jit->pc.ui++ = i -# define stack_framesize 128 +# define stack_framesize 224 # define _S0_REGNO 0x09 # define _S1_REGNO 0x0a # define _S2_REGNO 0x0b @@ -574,6 +574,7 @@ static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t); static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t); # define ldxi_ui(r0,r1,i0) _ldxi_ui(_jit,r0,r1,i0) static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t); +# define ldxr(r0,r1,r2) ldxr_l(r0,r1,r2) # define ldxr_l(r0,r1,r2) _ldxr_l(_jit,r0,r1,r2) static void _ldxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t); # define ldxi(r0,r1,i0) ldxi_l(r0,r1,i0) @@ -648,6 +649,10 @@ static jit_word_t _calli_p(jit_state_t*, jit_word_t); static void _prolog(jit_state_t*,jit_node_t*); # define epilog(node) _epilog(_jit,node) 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 @@ -2618,6 +2623,13 @@ _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) { + for (reg = _jitc->function->self.argi; jit_arg_reg_p(reg); ++reg) + stxi(stack_framesize - 48 + reg * 8, _FP_REGNO, rn(_A0 - reg)); + for (reg = _jitc->function->self.argi; jit_arg_reg_p(reg); ++reg) + stxi_d(stack_framesize - 96 + reg * 8, _FP_REGNO, rn(_F16 - reg)); + } } static void @@ -2656,6 +2668,55 @@ _epilog(jit_state_t *_jit, jit_node_t *node) * other values are reserved */ } +static void +_vastart(jit_state_t *_jit, jit_int32_t r0) +{ + jit_int32_t reg; + + /* Return jit_va_list_t in the register argument */ + addi(r0, _FP_REGNO, _jitc->function->vaoff); + + reg = jit_get_reg(jit_class_gpr); + + /* The base field is constant. */ + addi(rn(reg), _FP_REGNO, stack_framesize - 48); + stxi(offsetof(jit_va_list_t, base), r0, rn(reg)); + + /* Initialize the offset field */ + movi(rn(reg), _jitc->function->vagp * 8); + stxi(offsetof(jit_va_list_t, offset), 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 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 base in first temporary. */ + ldxi(rn(rg0), r1, offsetof(jit_va_list_t, base)); + + /* Load the offset in the second temporary. */ + ldxi(rn(rg1), r1, offsetof(jit_va_list_t, offset)); + + /* Load the argument */ + ldxr(r0, rn(rg0), rn(rg1)); + + /* No longer needed. */ + jit_unget_reg(rg0); + + /* Update offset. */ + addi(rn(rg1), rn(rg1), 8); + stxi(offsetof(jit_va_list_t, offset), r1, rn(rg1)); + jit_unget_reg(rg1); +} + static void _patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label) { diff --git a/lib/jit_alpha-fpu.c b/lib/jit_alpha-fpu.c index a26b9ae9d..9d9143b37 100644 --- a/lib/jit_alpha-fpu.c +++ b/lib/jit_alpha-fpu.c @@ -586,6 +586,8 @@ static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t); static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t); # define stxi_d(i0,r0,r1) _stxi_d(_jit,i0,r0,r1) static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t); +# 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 @@ -1543,4 +1545,39 @@ _stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1) jit_unget_reg(reg); } } + +static void +_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1) +{ + jit_word_t ge_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 base in first temporary. */ + ldxi(rn(rg0), r1, offsetof(jit_va_list_t, base)); + + /* Load the offset in the second temporary. */ + ldxi(rn(rg1), r1, offsetof(jit_va_list_t, offset)); + + /* Jump if overflowed register saved area. */ + ge_code = bgei(_jit->pc.w, rn(rg1), 48); + /* Otherwise load from the float registers save area. */ + subi(rn(rg1), rn(rg1), 48); + patch_at(ge_code, _jit->pc.w); + + /* Load the argument */ + ldxr_d(r0, rn(rg0), rn(rg1)); + + /* No longer needed. */ + jit_unget_reg(rg0); + + /* Update offset. */ + addi(rn(rg1), rn(rg1), 8); + stxi(offsetof(jit_va_list_t, offset), r1, rn(rg1)); + jit_unget_reg(rg1); +} #endif diff --git a/lib/jit_alpha.c b/lib/jit_alpha.c index 7bb92e9da..02577d377 100644 --- a/lib/jit_alpha.c +++ b/lib/jit_alpha.c @@ -33,6 +33,30 @@ # define F_DISP 8 - sizeof(jit_float32_t) #endif +/* + * Types + */ +/* + * What I could understand from gcc/config/alpha/alpha.c:alpha_build_builtin_va_list() + * and other helpers, as well as objdump of simple test programs; could not + * get gdb working on the test system I had access... + * + * base-48 to base is where up to 6 float registers are saved. + * base to base+48 is where up to 6 integer registers are saved. + * base+48... is where varargs arguments are stored. + * + * if (offset < 48) { + * if (type == double) + * offset -= 48; + * } + * load(reg, base, offset); + * offset += 8; + */ +typedef struct jit_va_list { + jit_pointer_t base; + jit_word_t offset; +} jit_va_list_t; + /* * Prototypes */ @@ -186,7 +210,7 @@ void _jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v) { jit_int32_t reg; - assert(_jitc->function); + assert(_jitc->function != NULL); if (!_jitc->function->allocar) { _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t)); _jitc->function->allocar = 1; @@ -295,6 +319,10 @@ _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)); + _jitc->function->vagp = _jitc->function->self.argi; } } @@ -1252,9 +1280,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(); @@ -1274,7 +1312,7 @@ _emit_code(jit_state_t *_jit) } } jit_regarg_clr(node, value); - assert(_jitc->regarg == jit_carry == _NOREG ? 0 : (1 << jit_carry)); + assert(_jitc->regarg == (jit_carry == _NOREG) ? 0 : (1 << jit_carry)); /* update register live state */ jit_reglive(node); }