From 1c9088beca341765f5260a1ae6f3289b494d4eb8 Mon Sep 17 00:00:00 2001 From: pcpa Date: Mon, 3 Dec 2012 14:27:27 -0200 Subject: [PATCH] Update code to build and pass test cases in the arm port. * configure.ac, include/lightning/jit_private.h, lib/jit_arm-cpu.c, lib/jit_arm-swf.c, lib/jit_arm.c, check/Makefile.am: Correct implementation of the arm backend port to build and pass the current test cases. Tested on armv7 with softfp abi. * lib/jit_disasm.c: Rename and change prototype of static disassemble function as in the arm backend it is required to access state information stored in the jit_state_t object. * check/3to2.tst, check/add.tst: Correct test case code assuming JIT_RO and JIT_RET are the same, and even if they are the same, the logic was incorrect because it must always call jit_retval* to fetch a function call return before any other instruction. The arm backend hash a special condition if jit_retval is not called, because "r0" is not JIT_R0, but is JIT_RET and *also* the first argument for a called function, so JIT_RET must be only used as an argument to jit_retval. * TODO: New file listing important tasks to be resolved. --- ChangeLog | 20 ++++++++++ TODO | 11 ++++++ check/3to2.tst | 6 ++- check/Makefile.am | 2 +- check/add.tst | 1 + configure.ac | 4 ++ include/lightning/jit_private.h | 10 ++++- lib/jit_arm-cpu.c | 14 ++++--- lib/jit_arm-swf.c | 6 ++- lib/jit_arm.c | 65 +++++++++++++++++++-------------- lib/jit_disasm.c | 32 ++++++++-------- 11 files changed, 119 insertions(+), 52 deletions(-) create mode 100644 TODO diff --git a/ChangeLog b/ChangeLog index 760d29ee4..87da374d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2012-12-03 Paulo Andrade + + * configure.ac, include/lightning/jit_private.h, lib/jit_arm-cpu.c, + lib/jit_arm-swf.c, lib/jit_arm.c, check/Makefile.am: Correct + implementation of the arm backend port to build and pass the + current test cases. Tested on armv7 with softfp abi. + + * lib/jit_disasm.c: Rename and change prototype of static + disassemble function as in the arm backend it is required + to access state information stored in the jit_state_t object. + + * check/3to2.tst, check/add.tst: Correct test case code assuming + JIT_RO and JIT_RET are the same, and even if they are the same, + the logic was incorrect because it must always call jit_retval* + to fetch a function call return before any other instruction. + The arm backend hash a special condition if jit_retval is not + called, because "r0" is not JIT_R0, but is JIT_RET and *also* + the first argument for a called function, so JIT_RET must be + only used as an argument to jit_retval. + 2012-12-03 Paulo Andrade * check/all.tst, check/lightning.c: Only declare or use 64 bit diff --git a/TODO b/TODO new file mode 100644 index 000000000..8cb265714 --- /dev/null +++ b/TODO @@ -0,0 +1,11 @@ + * Remove JIT_RET and JIT_FRET. Only interface to these should + be jit_retval, jit_retval_f and jit_retval_d, otherwise one + may use JIT_RET and/or JIT_FRET as argument to other jit calls, + what may cause problems at least on the arm backend. + + * Update documentation to match new implementation. + + * Make an sparc port to not remove previous functionality. + + * Test and correct the ppc and mips ports, after the import and + adaptation of the code to lightning. diff --git a/check/3to2.tst b/check/3to2.tst index 5804ab6b1..10de7f891 100644 --- a/check/3to2.tst +++ b/check/3to2.tst @@ -22,9 +22,10 @@ test_double_##a##_##b##_##c: \ pushargi_d x \ pushargi_d y \ finishi test_double_##a##_##b##_##c \ + retval_d %f0 \ prepare 1 \ pushargi dfmt \ - pushargr_d %fret \ + pushargr_d %f0 \ finishi @printf #define def_test_int(a, b, c) \ @@ -42,9 +43,10 @@ test_int_##a##_##b##_##c: \ pushargi x \ pushargi y \ finishi test_int_##a##_##b##_##c \ + retval %r0 \ prepare 1 \ pushargi ifmt \ - pushargr %ret \ + pushargr %r0 \ finishi @printf def_test_double(f0, f0, f0) diff --git a/check/Makefile.am b/check/Makefile.am index 6445b6e88..450cee948 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -16,7 +16,7 @@ AM_CFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE check_PROGRAMS = lightning -lightning_LDADD = $(top_builddir)/lib/liblightning.la -ldl +lightning_LDADD = $(top_builddir)/lib/liblightning.la -lm -ldl $(top_builddir)/lib/liblightning.la: cd $(top_builddir)/lib; $(MAKE) $(AM_MAKEFLAGS) liblightning.la diff --git a/check/add.tst b/check/add.tst index 61500cd59..03a6962d2 100644 --- a/check/add.tst +++ b/check/add.tst @@ -21,6 +21,7 @@ main: pushargi 5 pushargi 4 finishi test + retval %r0 prepare 1 pushargi fmt pushargi 5 diff --git a/configure.ac b/configure.ac index bac8e0508..de78e10c8 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,10 @@ AM_CONDITIONAL(cpu_arm, [test cpu-$cpu = cpu-arm]) AM_CONDITIONAL(cpu_mips, [test cpu-$cpu = cpu-mips]) AM_CONDITIONAL(cpu_ppc, [test cpu-$cpu = cpu-ppc]) AM_CONDITIONAL(cpu_x86, [test cpu-$cpu = cpu-x86]) +if test $cpu = arm; then + AC_CHECK_LIB(m, sqrtf, , + [AC_MSG_ERROR([sqrtf required but not available])]) +fi AC_SUBST([LIGHTNING_CFLAGS]) diff --git a/include/lightning/jit_private.h b/include/lightning/jit_private.h index fca88eea4..afbfd10ca 100644 --- a/include/lightning/jit_private.h +++ b/include/lightning/jit_private.h @@ -261,10 +261,18 @@ struct jit_state { # if DISASSEMBLER struct { jit_data_info_t *ptr; - it_word_t offset; + jit_word_t offset; jit_word_t length; } data_info; /* constant pools information */ # endif + /* Note that this field is somewhat hackish, but required by most + * ways to implement jit, unless implementing a pure one function + * per jit, as most times it needs to start the jit buffer with a + * jump where the "main" prolog starts, and because the initial + * code is in "arm mode", need to make an "arm mode" patch on that + * jump. A good example is the test suite assembler, where most + * test cases start with a "jmpi main" call. */ + jit_uword_t thumb; struct { jit_uint8_t *data; /* pointer to code */ jit_word_t size; /* size data */ diff --git a/lib/jit_arm-cpu.c b/lib/jit_arm-cpu.c index 089ad388a..ff2b31944 100644 --- a/lib/jit_arm-cpu.c +++ b/lib/jit_arm-cpu.c @@ -203,8 +203,8 @@ extern unsigned __aeabi_uidivmod(unsigned, unsigned); # define THUMB2_CMNI 0xf1100000 # define ARM_TST 0x01100000 # define THUMB_TST 0x4200 -# define THUMB2_TST 0xea100f00 -# define THUMB2_TSTI 0xf0100f00 +# define THUMB2_TST 0xea100000 +# define THUMB2_TSTI 0xf0100000 # define ARM_TEQ 0x01300000 /* branch */ # define ARM_BX 0x012fff10 @@ -2429,7 +2429,8 @@ _jmpi(jit_state_t *_jit, jit_word_t i0) jit_word_t w; jit_word_t d; w = _jit->pc.w; - if (jit_thumb_p()) { + /* if thumb and in thumb mode */ + if (jit_thumb_p() && _jit->thumb) { d = ((i0 - w) >> 1) - 2; if (d >= -1024 && d <= 1023) T1_B(d & 0x7ff); @@ -2460,7 +2461,8 @@ _jmpi_p(jit_state_t *_jit, jit_word_t i0) jit_word_t w; jit_word_t d; w = _jit->pc.w; - if (jit_thumb_p()) { + /* if thumb and in thumb mode */ + if (jit_thumb_p() && _jit->thumb) { d = ((i0 - w) >> 1) - 2; assert(_s24P(d)); T2_B(encode_thumb_jump(d)); @@ -3569,6 +3571,8 @@ _prolog(jit_state_t *_jit, jit_node_t *node) * a pointer to a jit function) */ ADDI(_R12_REGNO, _R15_REGNO, 1); BX(_R12_REGNO); + if (!_jit->thumb) + _jit->thumb = _jit->pc.w; if (jit_cpu.abi) { T2_PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO)); VPUSH_F64(_D8_REGNO, 8); @@ -3617,7 +3621,7 @@ _patch_at(jit_state_t *_jit, } u; u.w = instr; if (kind == arm_patch_jump) { - if (jit_thumb_p()) { + if (jit_thumb_p() && instr >= _jit->thumb) { code2thumb(thumb.s[0], thumb.s[1], u.s[0], u.s[1]); if ((thumb.i & THUMB2_B) == THUMB2_B) { d = ((label - instr) >> 1) - 2; diff --git a/lib/jit_arm-swf.c b/lib/jit_arm-swf.c index 9155ff8f8..cc311dfb4 100644 --- a/lib/jit_arm-swf.c +++ b/lib/jit_arm-swf.c @@ -18,6 +18,8 @@ #if PROTO /* match vfpv3 result */ #define NAN_TO_INT_IS_ZERO 1 +extern float sqrtf(float); +extern double sqrt(double); extern float __addsf3(float, float); extern double __adddf3(double, double); extern float __aeabi_fsub(float, float); @@ -47,7 +49,7 @@ extern int __aeabi_dcmpun(double, double); # define swf_ff(i0,r0,r1) _swf_ff(_jit,i0,r0,r1) static void _swf_ff(jit_state_t*,float(*)(float),jit_int32_t,jit_int32_t) maybe_unused; -# define swf_dd(i0,r0,r1) _swf_id(_jit,i0,r0,r1) +# define swf_dd(i0,r0,r1) _swf_dd(_jit,i0,r0,r1) static void _swf_dd(jit_state_t*,double(*)(double),jit_int32_t,jit_int32_t) maybe_unused; # define swf_fff(i0,r0,r1,r2) _swf_fff(_jit,i0,r0,r1,r2) @@ -138,6 +140,8 @@ static void _swf_absr_d(jit_state_t*,jit_int32_t,jit_int32_t); static void _swf_negr_f(jit_state_t*,jit_int32_t,jit_int32_t); # define swf_negr_d(r0,r1) _swf_negr_d(_jit,r0,r1) static void _swf_negr_d(jit_state_t*,jit_int32_t,jit_int32_t); +# define swf_sqrtr_f(r0,r1) swf_ff(sqrtf,r0,r1) +# define swf_sqrtr_d(r0,r1) swf_dd(sqrt,r0,r1) # define swf_addr_f(r0,r1,r2) swf_fff(__addsf3,r0,r1,r2) # define swf_addi_f(r0,r1,i0) swf_fff_(__addsf3,r0,r1,i0) # define swf_addr_d(r0,r1,r2) swf_ddd(__adddf3,r0,r1,r2) diff --git a/lib/jit_arm.c b/lib/jit_arm.c index d75136a8c..319703e72 100644 --- a/lib/jit_arm.c +++ b/lib/jit_arm.c @@ -189,7 +189,7 @@ void _jit_init(jit_state_t *_jit) { jit_int32_t regno; - _jit->reglen = esize(_rvs) - 1; + _jit->reglen = jit_size(_rvs) - 1; /* jit_get_cpu() should have been already called, and only once */ if (!jit_cpu.vfp) { /* cause register to never be allocated, because simple @@ -212,7 +212,7 @@ _jit_prolog(jit_state_t *_jit) jit_epilog(); assert(jit_regset_cmp_ui(_jit->regarg, 0) == 0); jit_regset_set_ui(_jit->regsav, 0); - offset = _jit->functions->offset; + offset = _jit->functions.offset; if (offset >= _jit->functions.length) { _jit->functions.ptr = realloc(_jit->functions.ptr, (_jit->functions.length + 16) * @@ -320,7 +320,6 @@ void _jit_epilog(jit_state_t *_jit) { assert(_jit->function); - _jit->function->stack = ((_jit->function->self.alen - /* align stack at 8 bytes */ _jit->function->self.aoff) + 7) & -8; @@ -344,7 +343,7 @@ _jit_arg(jit_state_t *_jit) return (offset); } -ebool_t +jit_bool_t _jit_arg_reg_p(jit_state_t *_jit, jit_int32_t offset) { return (offset >= 0 && offset < 4); @@ -367,7 +366,7 @@ _jit_arg_f(jit_state_t *_jit) return (offset); } -ebool_t +jit_bool_t _jit_arg_f_reg_p(jit_state_t *_jit, jit_int32_t offset) { return (jit_arg_reg_p(offset)); @@ -402,7 +401,7 @@ _jit_arg_d(jit_state_t *_jit) return (offset); } -ebool_t +jit_bool_t _jit_arg_d_reg_p(jit_state_t *_jit, jit_int32_t offset) { return (jit_arg_reg_p(offset)); @@ -543,7 +542,7 @@ _jit_pushargr_f(jit_state_t *_jit, jit_int32_t u) } void -_jit_pushargi_f(jit_state_t *_jit, efloat32_t u) +_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u) { jit_int32_t regno; @@ -598,7 +597,7 @@ _jit_pushargr_d(jit_state_t *_jit, jit_int32_t u) } void -_jit_pushargi_d(jit_state_t *_jit, efloat64_t u) +_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u) { jit_int32_t regno; @@ -746,22 +745,24 @@ _jit_emit(jit_state_t *_jit) jit_node_t *node; jit_uint8_t *data; jit_word_t word; + jit_uword_t thumb; jit_int32_t info_offset; jit_int32_t const_offset; jit_int32_t patch_offset; } undo; - jit_epilog(); + if (_jit->function) + jit_epilog(); jit_optimize(); _jit->emit = 1; - _jit->code_length = 16 * 1024 * 1024; - _jit->code = mmap(NULL, _jit->code_length, - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0); + _jit->code.length = 16 * 1024 * 1024; + _jit->code.ptr = mmap(NULL, _jit->code.length, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); assert(_jit->code.ptr != MAP_FAILED); - _jit->pc.uc = _jit->code; + _jit->pc.uc = _jit->code.ptr; /* clear jit_flag_patch from label nodes if reallocating buffer * and starting over @@ -774,6 +775,7 @@ _jit_emit(jit_state_t *_jit) undo.word = 0; undo.node = NULL; undo.data = NULL; + undo.thumb = 0; undo.info_offset = undo.const_offset = undo.patch_offset = 0; # define assert_data(node) /**/ #define case_rr(name, type) \ @@ -1147,6 +1149,7 @@ _jit_emit(jit_state_t *_jit) case_vvf(div); case_vv(abs, _f); case_vv(neg, _f); + case_vv(sqrt, _f); case_vv(ext, _f); case_vv(ld, _f); case_vw(ld, _f); @@ -1231,6 +1234,7 @@ _jit_emit(jit_state_t *_jit) case_vvd(div); case_vv(abs, _d); case_vv(neg, _d); + case_vv(sqrt, _d); case_vv(ext, _d); case_vv(ld, _d); case_vw(ld, _d); @@ -1344,9 +1348,10 @@ _jit_emit(jit_state_t *_jit) undo.node = node; undo.word = _jit->pc.w; undo.data = _jit->consts.data; + undo.thumb = _jit->thumb; undo.const_offset = _jit->consts.offset; undo.patch_offset = _jit->patches.offset; - if (_jit->data_info) + if (_jit->data_info.ptr) undo.info_offset = _jit->data_info.offset; restart_function: _jit->again = 0; @@ -1365,9 +1370,10 @@ _jit_emit(jit_state_t *_jit) _jit->pc.w = undo.word; invalidate_consts(); _jit->consts.data = undo.data; + _jit->thumb = undo.thumb; _jit->consts.offset = undo.const_offset; _jit->patches.offset = undo.patch_offset; - if (_jit->data_info) + if (_jit->data_info.ptr) _jit->data_info.offset = undo.info_offset; goto restart_function; } @@ -1423,9 +1429,9 @@ _jit_emit(jit_state_t *_jit) flush_consts(); for (offset = 0; offset < _jit->patches.offset; offset++) { - assert(patches[offset] & arm_patch_node); + assert(_jit->patches.ptr[offset].kind & arm_patch_node); node = _jit->patches.ptr[offset].node; - word = _jit->patches[offset].inst; + word = _jit->patches.ptr[offset].inst; if (node->code == jit_code_movi) { if (jit_thumb_p()) value = node->v.n->u.w; @@ -1446,7 +1452,7 @@ _jit_emit(jit_state_t *_jit) } else value = node->u.n->u.w; - patch_at(patches[offset] & ~arm_patch_node, word, value); + patch_at(_jit->patches.ptr[offset].kind & ~arm_patch_node, word, value); } __clear_cache(_jit->code.ptr, _jit->pc.uc); @@ -1618,7 +1624,6 @@ _flush_consts(jit_state_t *_jit) { jit_word_t word; jit_int32_t offset; - jit_word_t *vector; /* if no forward constants */ if (!_jit->consts.length) @@ -1632,12 +1637,18 @@ _flush_consts(jit_state_t *_jit) memcpy(_jit->consts.data, _jit->consts.values, _jit->consts.size); _jit->pc.w += _jit->consts.size; - if (_jit->data_info) { - if (_jit->data_info->offset + 2 >= _jit->data_info->length) - erenew_vector(_jit->data_info, _jit->data_info->length + 1024); - vector = _jit->data_info->v.obj; - vector[_jit->data_info->offset++] = word; - vector[_jit->data_info->offset++] = _jit->consts.size; + if (_jit->data_info.ptr) { + if (_jit->data_info.offset >= _jit->data_info.length) { + _jit->data_info.ptr = realloc(_jit->data_info.ptr, + (_jit->data_info.length + 1024) * + sizeof(jit_data_info_t)); + memset(_jit->data_info.ptr + _jit->data_info.length, 0, + 1024 * sizeof(jit_data_info_t)); + _jit->data_info.length += 1024; + } + _jit->data_info.ptr[_jit->data_info.offset].code = word; + _jit->data_info.ptr[_jit->data_info.offset].length = _jit->consts.size; + ++_jit->data_info.offset; } for (offset = 0; offset < _jit->consts.offset; offset += 2) @@ -1687,7 +1698,7 @@ _patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node) _jit->patches.length += 1024; } _jit->patches.ptr[_jit->patches.offset].kind = kind; - _jit->patches.ptr[_jit->patches.offset].instr = instr; + _jit->patches.ptr[_jit->patches.offset].inst = instr; _jit->patches.ptr[_jit->patches.offset].node = node; ++_jit->patches.offset; } diff --git a/lib/jit_disasm.c b/lib/jit_disasm.c index 625419bae..c0a5079b0 100644 --- a/lib/jit_disasm.c +++ b/lib/jit_disasm.c @@ -29,8 +29,9 @@ disasm_compare_symbols(const void *ap, const void *bp); static void disasm_print_address(bfd_vma addr, struct disassemble_info *info); +#define disassemble(u, v) _disassemble(_jit, u, v) static void -disassemble(jit_pointer_t code, jit_int32_t length); +_disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length); #endif /* @@ -238,19 +239,20 @@ disasm_print_address(bfd_vma addr, struct disassemble_info *info) } static void -disassemble(jit_pointer_t code, jit_int32_t length) +_disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length) { - int bytes; + int bytes; #if __arm__ - jit_data_info_t *data_info; - jit_int32_t data_offset; + jit_int32_t offset; + jit_bool_t data_info; + jit_int32_t data_offset; #endif - bfd_vma pc = (jit_uword_t)code; - bfd_vma end = (jit_uword_t)code + length; - char buffer[address_buffer_length]; + bfd_vma pc = (jit_uword_t)code; + bfd_vma end = (jit_uword_t)code + length; + char buffer[address_buffer_length]; #if __arm__ - data_info = _jit->data_info; + data_info = 1; data_offset = 0; #endif disasm_info.buffer = code; @@ -260,16 +262,16 @@ disassemble(jit_pointer_t code, jit_int32_t length) #if __arm__ again: if (data_info) { - while (data_info.ptr[data_offset].code < pc) { + while (_jit->data_info.ptr[data_offset].code < pc) { data_offset += 2; - if (data_offset >= data_info.length) { - data_info = NULL; + if (data_offset >= _jit->data_info.length) { + data_info = 0; goto again; } } - if (pc == data_info.ptr[data_offset].code) { - line = data_info.ptr[data_offset].length; - for (; line >= 4; line -= 4, pc += 4) { + if (pc == _jit->data_info.ptr[data_offset].code) { + offset = _jit->data_info.ptr[data_offset].length; + for (; offset >= 4; offset -= 4, pc += 4) { bytes = sprintf(buffer, address_buffer_format, pc); (*disasm_info.fprintf_func)(disasm_stream, "%*c0x%s\t.data\t0x%08x\n",