mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-08 10:50:21 +02:00
* include/lightning.h, include/lightning/jit_private.h, lib/jit_names.c, lib/lightning.c: Add initial support for the new jit_va_start, jit_va_arg, jit_va_arg_d, and jit_va_end interfaces. The jit_va_start call is supposed to return a va_list compatible pointer, but not yet decided if it will be "declared" stdarg compatible, as for now only x86 support has been added (and should be compatible), but issues may arise on other backends. * check/lightning.c: Add wrappers to call the new jit_va_* interfaces. * lib/jit_x86-cpu.c, lib/jit_x86.c: Implement the new jit_va_* for x86. * lib/jit_x86-sz.c: Add fields, but not yet fully updated, as this is an intermediate commit. * lib/jit_aarch64-sz.c, lib/jit_aarch64.c, lib/jit_alpha-sz.c, lib/jit_alpha.c, lib/jit_arm-sz.c, lib/jit_arm.c, lib/jit_hppa-sz.c, lib/jit_hppa.c, lib/jit_ia64-sz.c, lib/jit_ia64.c, lib/jit_mips-sz.c, lib/jit_mips.c, lib/jit_ppc-sz.c, lib/jit_ppc.c, lib/jit_s390-sz.c, lib/jit_s390.c, lib/jit_sparc-sz.c, lib/jit_sparc.c: Prepare for the new jit_va_* interfaces. Not yet implemented, and will cause an assertion if used. * check/va_list.tst: Simple early test case, that works on x86_64, x32, ix86, cygwin, and cygwin64.
1466 lines
35 KiB
C
1466 lines
35 KiB
C
/*
|
|
* Copyright (C) 2013-2015 Free Software Foundation, Inc.
|
|
*
|
|
* This file is part of GNU lightning.
|
|
*
|
|
* GNU lightning is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* GNU lightning is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
* License for more details.
|
|
*
|
|
* Authors:
|
|
* Paulo Cesar Pereira de Andrade
|
|
*/
|
|
|
|
#include <lightning.h>
|
|
#include <lightning/jit_private.h>
|
|
|
|
#define rc(value) jit_class_##value
|
|
#define rn(reg) (jit_regno(_rvs[jit_regno(reg)].spec))
|
|
#if __WORDSIZE == 32
|
|
# define NUM_FLOAT_REG_ARGS 2
|
|
#else
|
|
# define NUM_FLOAT_REG_ARGS 4
|
|
#endif
|
|
#define jit_arg_reg_p(i) ((i) >= 0 && (i) < 5)
|
|
#define jit_arg_f_reg_p(i) ((i) >= 0 && (i) < NUM_FLOAT_REG_ARGS)
|
|
|
|
/*
|
|
* Prototypes
|
|
*/
|
|
#define jit_get_reg_pair() _jit_get_reg_pair(_jit)
|
|
static jit_int32_t _jit_get_reg_pair(jit_state_t*);
|
|
#define jit_unget_reg_pair(regno) _jit_unget_reg_pair(_jit,regno)
|
|
static void _jit_unget_reg_pair(jit_state_t*,jit_int32_t);
|
|
#define jit_get_reg_but_zero(flags) _jit_get_reg_but_zero(_jit,flags)
|
|
static jit_int32_t _jit_get_reg_but_zero(jit_state_t*,jit_int32_t);
|
|
#define jit_unget_reg_but_zero(reg) jit_unget_reg(reg)
|
|
#define patch(instr, node) _patch(_jit, instr, node)
|
|
static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
|
|
|
|
/* libgcc */
|
|
extern void __clear_cache(void *, void *);
|
|
|
|
#define PROTO 1
|
|
# include "jit_s390-cpu.c"
|
|
# include "jit_s390-fpu.c"
|
|
#undef PROTO
|
|
|
|
/*
|
|
* Initialization
|
|
*/
|
|
jit_register_t _rvs[] = {
|
|
{ rc(gpr) | 0x0, "%r0" },
|
|
{ rc(gpr) | 0x1, "%r1" },
|
|
{ rc(gpr) | rc(sav) | 0xc, "%r12" },
|
|
{ rc(gpr) | rc(sav) | 0xb, "%r11" },
|
|
{ rc(gpr) | rc(sav) | 0xa, "%r10" },
|
|
{ rc(gpr) | rc(sav) | 0x9, "%r9" },
|
|
{ rc(gpr) | rc(sav) | 0x8, "%r8" },
|
|
{ rc(gpr) | rc(sav) | 0x7, "%r7" },
|
|
{ rc(gpr) | rc(arg) | rc(sav) | 0x6,"%r6" },
|
|
{ rc(gpr) | rc(arg) | 0x5, "%r5" },
|
|
{ rc(gpr) | rc(arg) | 0x4, "%r4" },
|
|
{ rc(gpr) | rc(arg) | 0x3, "%r3" },
|
|
{ rc(gpr) | rc(arg) | 0x2, "%r2" },
|
|
{ rc(sav) | 0xd, "%r13" }, /* used as JIT_FP */
|
|
{ 0xe, "%r14" },
|
|
{ rc(sav) | 0xf, "%r15" },
|
|
{ rc(fpr) | 0x1, "%f1" },
|
|
{ rc(fpr) | 0x3, "%f3" },
|
|
{ rc(fpr) | 0x5, "%f5" },
|
|
{ rc(fpr) | 0x7, "%f7" },
|
|
{ rc(fpr) | rc(sav) | 0xe, "%f14" },
|
|
/* Do not use as temporary to simplify stack layout */
|
|
{ 0xf, "%f15" },
|
|
{ rc(fpr) | rc(sav) | 0x8, "%f8" },
|
|
{ rc(fpr) | rc(sav) | 0x9, "%f9" },
|
|
{ rc(fpr) | rc(sav) | 0xa, "%f10" },
|
|
{ rc(fpr) | rc(sav) | 0xb, "%f11" },
|
|
{ rc(fpr) | rc(sav) | 0xc, "%f12" },
|
|
{ rc(fpr) | rc(sav) | 0xd, "%f13" },
|
|
{ rc(fpr) | rc(arg) | 0x6, "%f6" },
|
|
{ rc(fpr) | rc(arg) | 0x4, "%f4" },
|
|
{ rc(fpr) | rc(arg) | 0x2, "%f2" },
|
|
{ rc(fpr) | rc(arg) | 0x0, "%f0" },
|
|
{ _NOREG, "<none>" },
|
|
};
|
|
|
|
/*
|
|
* Implementation
|
|
*/
|
|
void
|
|
jit_get_cpu(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
_jit_init(jit_state_t *_jit)
|
|
{
|
|
_jitc->reglen = jit_size(_rvs) - 1;
|
|
}
|
|
|
|
void
|
|
_jit_prolog(jit_state_t *_jit)
|
|
{
|
|
jit_int32_t offset;
|
|
|
|
if (_jitc->function)
|
|
jit_epilog();
|
|
assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
|
|
jit_regset_set_ui(&_jitc->regsav, 0);
|
|
offset = _jitc->functions.offset;
|
|
if (offset >= _jitc->functions.length) {
|
|
jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
|
|
_jitc->functions.length * sizeof(jit_function_t),
|
|
(_jitc->functions.length + 16) * sizeof(jit_function_t));
|
|
_jitc->functions.length += 16;
|
|
}
|
|
_jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
|
|
_jitc->function->self.size = stack_framesize;
|
|
_jitc->function->self.argi = _jitc->function->self.argf =
|
|
_jitc->function->self.aoff = _jitc->function->self.alen = 0;
|
|
/* preallocate 8 bytes if not using a constant data buffer */
|
|
if (_jitc->no_data)
|
|
_jitc->function->self.aoff = -8;
|
|
_jitc->function->self.call = jit_call_default;
|
|
jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
|
|
_jitc->reglen * sizeof(jit_int32_t));
|
|
|
|
_jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
|
|
jit_link(_jitc->function->prolog);
|
|
_jitc->function->prolog->w.w = offset;
|
|
_jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
|
|
/* u: label value
|
|
* v: offset in blocks vector
|
|
* w: offset in functions vector
|
|
*/
|
|
_jitc->function->epilog->w.w = offset;
|
|
|
|
jit_regset_new(&_jitc->function->regset);
|
|
}
|
|
|
|
jit_int32_t
|
|
_jit_allocai(jit_state_t *_jit, jit_int32_t length)
|
|
{
|
|
assert(_jitc->function);
|
|
switch (length) {
|
|
case 0: case 1: break;
|
|
case 2: _jitc->function->self.aoff &= -2; break;
|
|
case 3: case 4: _jitc->function->self.aoff &= -4; break;
|
|
default: _jitc->function->self.aoff &= -8; break;
|
|
}
|
|
_jitc->function->self.aoff -= length;
|
|
return (_jitc->function->self.aoff);
|
|
}
|
|
|
|
void
|
|
_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
|
|
{
|
|
jit_int32_t reg;
|
|
assert(_jitc->function);
|
|
if (!_jitc->function->allocar) {
|
|
_jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
|
|
_jitc->function->allocar = 1;
|
|
}
|
|
reg = jit_get_reg(jit_class_gpr);
|
|
jit_negr(reg, v);
|
|
jit_andi(reg, reg, -8);
|
|
jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
|
|
jit_addr(u, u, reg);
|
|
jit_addr(JIT_SP, JIT_SP, reg);
|
|
jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
|
|
jit_unget_reg(reg);
|
|
}
|
|
|
|
void
|
|
_jit_ret(jit_state_t *_jit)
|
|
{
|
|
jit_node_t *instr;
|
|
|
|
assert(_jitc->function);
|
|
|
|
/* jump to epilog */
|
|
instr = jit_jmpi();
|
|
jit_patch_at(instr, _jitc->function->epilog);
|
|
}
|
|
|
|
void
|
|
_jit_retr(jit_state_t *_jit, jit_int32_t u)
|
|
{
|
|
jit_movr(JIT_RET, u);
|
|
jit_ret();
|
|
}
|
|
|
|
void
|
|
_jit_reti(jit_state_t *_jit, jit_word_t u)
|
|
{
|
|
jit_movi(JIT_RET, u);
|
|
jit_ret();
|
|
}
|
|
|
|
void
|
|
_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
|
|
{
|
|
jit_movr_f(JIT_FRET, u);
|
|
jit_ret();
|
|
}
|
|
|
|
void
|
|
_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
|
|
{
|
|
jit_movi_f(JIT_FRET, u);
|
|
jit_ret();
|
|
}
|
|
|
|
void
|
|
_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
|
|
{
|
|
jit_movr_d(JIT_FRET, u);
|
|
jit_ret();
|
|
}
|
|
|
|
void
|
|
_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
|
|
{
|
|
jit_movi_d(JIT_FRET, u);
|
|
jit_ret();
|
|
}
|
|
|
|
void
|
|
_jit_epilog(jit_state_t *_jit)
|
|
{
|
|
assert(_jitc->function);
|
|
assert(_jitc->function->epilog->next == NULL);
|
|
jit_link(_jitc->function->epilog);
|
|
_jitc->function = NULL;
|
|
}
|
|
|
|
jit_bool_t
|
|
_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
|
|
{
|
|
if (u->code == jit_code_arg)
|
|
return (jit_arg_reg_p(u->u.w));
|
|
assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
|
|
return (jit_arg_f_reg_p(u->u.w));
|
|
}
|
|
|
|
void
|
|
_jit_ellipsis(jit_state_t *_jit)
|
|
{
|
|
if (_jitc->prepare) {
|
|
assert(!(_jitc->function->call.call & jit_call_varargs));
|
|
_jitc->function->call.call |= jit_call_varargs;
|
|
}
|
|
else {
|
|
assert(!(_jitc->function->self.call & jit_call_varargs));
|
|
_jitc->function->self.call |= jit_call_varargs;
|
|
}
|
|
}
|
|
|
|
jit_node_t *
|
|
_jit_arg(jit_state_t *_jit)
|
|
{
|
|
jit_int32_t offset;
|
|
assert(_jitc->function);
|
|
if (jit_arg_reg_p(_jitc->function->self.argi))
|
|
offset = _jitc->function->self.argi++;
|
|
else {
|
|
offset = _jitc->function->self.size;
|
|
_jitc->function->self.size += sizeof(jit_word_t);
|
|
}
|
|
return (jit_new_node_w(jit_code_arg, offset));
|
|
}
|
|
|
|
jit_node_t *
|
|
_jit_arg_f(jit_state_t *_jit)
|
|
{
|
|
jit_int32_t offset;
|
|
assert(_jitc->function);
|
|
if (jit_arg_f_reg_p(_jitc->function->self.argf))
|
|
offset = _jitc->function->self.argf++;
|
|
else {
|
|
offset = _jitc->function->self.size;
|
|
_jitc->function->self.size += sizeof(jit_word_t);
|
|
}
|
|
return (jit_new_node_w(jit_code_arg_f, offset));
|
|
}
|
|
|
|
jit_node_t *
|
|
_jit_arg_d(jit_state_t *_jit)
|
|
{
|
|
jit_int32_t offset;
|
|
assert(_jitc->function);
|
|
if (jit_arg_f_reg_p(_jitc->function->self.argf))
|
|
offset = _jitc->function->self.argf++;
|
|
else {
|
|
offset = _jitc->function->self.size;
|
|
_jitc->function->self.size += sizeof(jit_float64_t);
|
|
}
|
|
return (jit_new_node_w(jit_code_arg_d, offset));
|
|
}
|
|
|
|
void
|
|
_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_extr_c(u, _R2 - v->u.w);
|
|
else
|
|
jit_ldxi_c(u, JIT_FP,
|
|
v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int8_t));
|
|
}
|
|
|
|
void
|
|
_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_extr_uc(u, _R2 - v->u.w);
|
|
else
|
|
jit_ldxi_uc(u, JIT_FP,
|
|
v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint8_t));
|
|
}
|
|
|
|
void
|
|
_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_extr_s(u, _R2 - v->u.w);
|
|
else
|
|
jit_ldxi_s(u, JIT_FP,
|
|
v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int16_t));
|
|
}
|
|
|
|
void
|
|
_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_extr_us(u, _R2 - v->u.w);
|
|
else
|
|
jit_ldxi_us(u, JIT_FP,
|
|
v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint16_t));
|
|
}
|
|
|
|
void
|
|
_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w)) {
|
|
#if __WORDSIZE == 32
|
|
jit_movr(u, _R2 - v->u.w);
|
|
#else
|
|
jit_extr_i(u, _R2 - v->u.w);
|
|
#endif
|
|
}
|
|
else
|
|
jit_ldxi_i(u, JIT_FP,
|
|
v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int32_t));
|
|
}
|
|
|
|
#if __WORDSIZE == 64
|
|
void
|
|
_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_extr_ui(u, _R2 - v->u.w);
|
|
else
|
|
jit_ldxi_ui(u, JIT_FP,
|
|
v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint32_t));
|
|
}
|
|
|
|
void
|
|
_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_movr(u, _R2 - v->u.w);
|
|
else
|
|
jit_ldxi_l(u, JIT_FP, v->u.w);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_movr(_R2 - v->u.w, u);
|
|
else
|
|
jit_stxi(v->u.w, JIT_FP, u);
|
|
}
|
|
|
|
void
|
|
_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
|
|
{
|
|
jit_int32_t regno;
|
|
assert(v->code == jit_code_arg);
|
|
if (jit_arg_reg_p(v->u.w))
|
|
jit_movi(_R2 - v->u.w, u);
|
|
else {
|
|
regno = jit_get_reg(jit_class_gpr);
|
|
jit_movi(regno, u);
|
|
jit_stxi(v->u.w, JIT_FP, regno);
|
|
jit_unget_reg(regno);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg_f);
|
|
if (jit_arg_f_reg_p(v->u.w))
|
|
jit_movr_f(u, _F0 - v->u.w);
|
|
else
|
|
jit_ldxi_f(u, JIT_FP,
|
|
v->u.w
|
|
#if __WORDSIZE == 64
|
|
+ (__WORDSIZE >> 3) - sizeof(jit_float32_t)
|
|
#endif
|
|
);
|
|
}
|
|
|
|
void
|
|
_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg_f);
|
|
if (jit_arg_f_reg_p(v->u.w))
|
|
jit_movr_f(_F0 - v->u.w, u);
|
|
else
|
|
jit_stxi_f(v->u.w
|
|
#if __WORDSIZE == 64
|
|
+ (__WORDSIZE >> 3) - sizeof(jit_float32_t)
|
|
#endif
|
|
, JIT_FP, u);
|
|
}
|
|
|
|
void
|
|
_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
|
|
{
|
|
jit_int32_t regno;
|
|
assert(v->code == jit_code_arg_f);
|
|
if (jit_arg_f_reg_p(v->u.w))
|
|
jit_movi_f(_F0 - v->u.w, u);
|
|
else {
|
|
regno = jit_get_reg(jit_class_fpr);
|
|
jit_movi_f(regno, u);
|
|
jit_stxi_f(v->u.w
|
|
#if __WORDSIZE == 64
|
|
+ (__WORDSIZE >> 3) - sizeof(jit_float32_t)
|
|
#endif
|
|
, JIT_FP, regno);
|
|
jit_unget_reg(regno);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg_d);
|
|
if (jit_arg_f_reg_p(v->u.w))
|
|
jit_movr_d(u, _F0 - v->u.w);
|
|
else
|
|
jit_ldxi_d(u, JIT_FP, v->u.w);
|
|
}
|
|
|
|
void
|
|
_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
|
|
{
|
|
assert(v->code == jit_code_arg_d);
|
|
if (jit_arg_f_reg_p(v->u.w))
|
|
jit_movr_d(_F0 - v->u.w, u);
|
|
else
|
|
jit_stxi_d(v->u.w, JIT_FP, u);
|
|
}
|
|
|
|
void
|
|
_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
|
|
{
|
|
jit_int32_t regno;
|
|
assert(v->code == jit_code_arg_d);
|
|
if (jit_arg_f_reg_p(v->u.w))
|
|
jit_movi_d(_F0 - v->u.w, u);
|
|
else {
|
|
regno = jit_get_reg(jit_class_fpr);
|
|
jit_movi_d(regno, u);
|
|
jit_stxi_d(v->u.w, JIT_FP, regno);
|
|
jit_unget_reg(regno);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
|
|
{
|
|
assert(_jitc->function);
|
|
if (jit_arg_reg_p(_jitc->function->call.argi)) {
|
|
jit_movr(_R2 - _jitc->function->call.argi, u);
|
|
++_jitc->function->call.argi;
|
|
}
|
|
else {
|
|
jit_stxi(_jitc->function->call.size + stack_framesize, JIT_SP, u);
|
|
_jitc->function->call.size += sizeof(jit_word_t);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_pushargi(jit_state_t *_jit, jit_word_t u)
|
|
{
|
|
jit_int32_t regno;
|
|
assert(_jitc->function);
|
|
if (jit_arg_reg_p(_jitc->function->call.argi)) {
|
|
jit_movi(_R2 - _jitc->function->call.argi, u);
|
|
++_jitc->function->call.argi;
|
|
}
|
|
else {
|
|
regno = jit_get_reg(jit_class_gpr);
|
|
jit_movi(regno, u);
|
|
jit_stxi(_jitc->function->call.size + stack_framesize, JIT_SP, regno);
|
|
jit_unget_reg(regno);
|
|
_jitc->function->call.size += sizeof(jit_word_t);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
|
|
{
|
|
assert(_jitc->function);
|
|
if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
|
|
jit_movr_f(_F0 - _jitc->function->call.argf, u);
|
|
++_jitc->function->call.argf;
|
|
}
|
|
else {
|
|
jit_stxi_f(_jitc->function->call.size + stack_framesize
|
|
#if __WORDSIZE == 64
|
|
+ (__WORDSIZE >> 3) - sizeof(jit_float32_t)
|
|
#endif
|
|
, JIT_SP, u);
|
|
_jitc->function->call.size += sizeof(jit_word_t);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
|
|
{
|
|
jit_int32_t regno;
|
|
assert(_jitc->function);
|
|
if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
|
|
jit_movi_f(_F0 - _jitc->function->call.argf, u);
|
|
++_jitc->function->call.argf;
|
|
}
|
|
else {
|
|
regno = jit_get_reg(jit_class_fpr);
|
|
jit_movi_f(regno, u);
|
|
jit_stxi_f(_jitc->function->call.size + stack_framesize
|
|
#if __WORDSIZE == 64
|
|
+ (__WORDSIZE >> 3) - sizeof(jit_float32_t)
|
|
#endif
|
|
, JIT_SP, regno);
|
|
jit_unget_reg(regno);
|
|
_jitc->function->call.size += sizeof(jit_word_t);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
|
|
{
|
|
assert(_jitc->function);
|
|
if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
|
|
jit_movr_d(_F0 - _jitc->function->call.argf, u);
|
|
++_jitc->function->call.argf;
|
|
}
|
|
else {
|
|
jit_stxi_d(_jitc->function->call.size + stack_framesize, JIT_SP, u);
|
|
_jitc->function->call.size += sizeof(jit_float64_t);
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
|
|
{
|
|
jit_int32_t regno;
|
|
assert(_jitc->function);
|
|
if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
|
|
jit_movi_d(_F0 - _jitc->function->call.argf, u);
|
|
++_jitc->function->call.argf;
|
|
}
|
|
else {
|
|
regno = jit_get_reg(jit_class_fpr);
|
|
jit_movi_d(regno, u);
|
|
jit_stxi_d(_jitc->function->call.size + stack_framesize, JIT_SP, regno);
|
|
jit_unget_reg(regno);
|
|
_jitc->function->call.size += sizeof(jit_float64_t);
|
|
}
|
|
}
|
|
|
|
jit_bool_t
|
|
_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
|
|
{
|
|
jit_int32_t spec;
|
|
spec = jit_class(_rvs[regno].spec);
|
|
if (spec & jit_class_arg) {
|
|
regno = _R2 - regno;
|
|
if (regno >= 0 && regno < node->v.w)
|
|
return (1);
|
|
if (spec & jit_class_fpr) {
|
|
regno = _F0 - regno;
|
|
if (regno >= 0 && regno < node->w.w)
|
|
return (1);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_node_t *call;
|
|
assert(_jitc->function);
|
|
if (_jitc->function->self.alen < _jitc->function->call.size)
|
|
_jitc->function->self.alen = _jitc->function->call.size;
|
|
call = jit_callr(r0);
|
|
call->v.w = _jitc->function->call.argi;
|
|
call->w.w = _jitc->function->call.argf;
|
|
_jitc->function->call.argi = _jitc->function->call.argf =
|
|
_jitc->function->call.size = 0;
|
|
_jitc->prepare = 0;
|
|
}
|
|
|
|
jit_node_t *
|
|
_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
|
|
{
|
|
jit_node_t *node;
|
|
assert(_jitc->function);
|
|
if (_jitc->function->self.alen < _jitc->function->call.size)
|
|
_jitc->function->self.alen = _jitc->function->call.size;
|
|
node = jit_calli(i0);
|
|
node->v.w = _jitc->function->call.argi;
|
|
node->w.w = _jitc->function->call.argf;
|
|
_jitc->function->call.argi = _jitc->function->call.argf =
|
|
_jitc->function->call.size = 0;
|
|
_jitc->prepare = 0;
|
|
return (node);
|
|
}
|
|
|
|
void
|
|
_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_extr_c(r0, JIT_RET);
|
|
}
|
|
|
|
void
|
|
_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_extr_uc(r0, JIT_RET);
|
|
}
|
|
|
|
void
|
|
_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_extr_s(r0, JIT_RET);
|
|
}
|
|
|
|
void
|
|
_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_extr_us(r0, JIT_RET);
|
|
}
|
|
|
|
void
|
|
_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
#if __WORDSIZE == 64
|
|
jit_extr_i(r0, JIT_RET);
|
|
#else
|
|
jit_movr(r0, JIT_RET);
|
|
#endif
|
|
}
|
|
|
|
#if __WORDSIZE == 64
|
|
void
|
|
_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_extr_ui(r0, JIT_RET);
|
|
}
|
|
|
|
void
|
|
_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_movr(r0, JIT_RET);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_movr_f(r0, JIT_FRET);
|
|
}
|
|
|
|
void
|
|
_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
|
|
{
|
|
jit_movr_d(r0, JIT_FRET);
|
|
}
|
|
|
|
jit_pointer_t
|
|
_emit_code(jit_state_t *_jit)
|
|
{
|
|
jit_node_t *node;
|
|
jit_node_t *temp;
|
|
jit_word_t word;
|
|
jit_int32_t value;
|
|
jit_int32_t offset;
|
|
struct {
|
|
jit_node_t *node;
|
|
jit_word_t word;
|
|
jit_int32_t patch_offset;
|
|
} undo;
|
|
|
|
_jitc->function = NULL;
|
|
|
|
jit_reglive_setup();
|
|
|
|
undo.word = 0;
|
|
undo.node = NULL;
|
|
undo.patch_offset = 0;
|
|
|
|
#define assert_data(node) /**/
|
|
#define case_rr(name, type) \
|
|
case jit_code_##name##r##type: \
|
|
name##r##type(rn(node->u.w), rn(node->v.w)); \
|
|
break
|
|
#define case_rw(name, type) \
|
|
case jit_code_##name##i##type: \
|
|
name##i##type(rn(node->u.w), node->v.w); \
|
|
break
|
|
#define case_wr(name, type) \
|
|
case jit_code_##name##i##type: \
|
|
name##i##type(node->u.w, rn(node->v.w)); \
|
|
break
|
|
#define case_rrr(name, type) \
|
|
case jit_code_##name##r##type: \
|
|
name##r##type(rn(node->u.w), \
|
|
rn(node->v.w), rn(node->w.w)); \
|
|
break
|
|
#define case_rrrr(name, type) \
|
|
case jit_code_##name##r##type: \
|
|
name##r##type(rn(node->u.q.l), rn(node->u.q.h), \
|
|
rn(node->v.w), rn(node->w.w)); \
|
|
break
|
|
#define case_rrw(name, type) \
|
|
case jit_code_##name##i##type: \
|
|
name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
|
|
break
|
|
#define case_rrrw(name, type) \
|
|
case jit_code_##name##i##type: \
|
|
name##i##type(rn(node->u.q.l), rn(node->u.q.h), \
|
|
rn(node->v.w), node->w.w); \
|
|
break
|
|
#define case_rrf(name) \
|
|
case jit_code_##name##i_f: \
|
|
assert_data(node); \
|
|
name##i_f(rn(node->u.w), rn(node->v.w), \
|
|
(jit_float32_t *)node->w.n->u.w); \
|
|
break
|
|
#define case_rrd(name) \
|
|
case jit_code_##name##i_d: \
|
|
assert_data(node); \
|
|
name##i_d(rn(node->u.w), rn(node->v.w), \
|
|
(jit_float64_t *)node->w.n->u.w); \
|
|
break
|
|
#define case_wrr(name, type) \
|
|
case jit_code_##name##i##type: \
|
|
name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
|
|
break
|
|
#define case_brr(name, type) \
|
|
case jit_code_##name##r##type: \
|
|
temp = node->u.n; \
|
|
assert(temp->code == jit_code_label || \
|
|
temp->code == jit_code_epilog); \
|
|
if (temp->flag & jit_flag_patch) \
|
|
name##r##type(temp->u.w, rn(node->v.w), \
|
|
rn(node->w.w)); \
|
|
else { \
|
|
word = name##r##type##_p(_jit->pc.w, \
|
|
rn(node->v.w), \
|
|
rn(node->w.w)); \
|
|
patch(word, node); \
|
|
} \
|
|
break
|
|
#define case_brw(name, type) \
|
|
case jit_code_##name##i##type: \
|
|
temp = node->u.n; \
|
|
assert(temp->code == jit_code_label || \
|
|
temp->code == jit_code_epilog); \
|
|
if (temp->flag & jit_flag_patch) \
|
|
name##i##type(temp->u.w, \
|
|
rn(node->v.w), node->w.w); \
|
|
else { \
|
|
word = name##i##type##_p(_jit->pc.w, \
|
|
rn(node->v.w), node->w.w); \
|
|
patch(word, node); \
|
|
} \
|
|
break;
|
|
#define case_brf(name) \
|
|
case jit_code_##name##i_f: \
|
|
temp = node->u.n; \
|
|
assert(temp->code == jit_code_label || \
|
|
temp->code == jit_code_epilog); \
|
|
if (temp->flag & jit_flag_patch) \
|
|
name##i_f(temp->u.w, rn(node->v.w), \
|
|
(jit_float32_t *)node->w.n->u.w); \
|
|
else { \
|
|
word = name##i_f_p(_jit->pc.w, rn(node->v.w), \
|
|
(jit_float32_t *)node->w.n->u.w);\
|
|
patch(word, node); \
|
|
} \
|
|
break
|
|
#define case_brd(name) \
|
|
case jit_code_##name##i_d: \
|
|
temp = node->u.n; \
|
|
assert(temp->code == jit_code_label || \
|
|
temp->code == jit_code_epilog); \
|
|
if (temp->flag & jit_flag_patch) \
|
|
name##i_d(temp->u.w, rn(node->v.w), \
|
|
(jit_float64_t *)node->w.n->u.w); \
|
|
else { \
|
|
word = name##i_d_p(_jit->pc.w, rn(node->v.w), \
|
|
(jit_float64_t *)node->w.n->u.w);\
|
|
patch(word, node); \
|
|
} \
|
|
break
|
|
for (node = _jitc->head; node; node = node->next) {
|
|
if (_jit->pc.uc >= _jitc->code.end)
|
|
return (NULL);
|
|
|
|
#if DEVEL_DISASSEMBLER
|
|
node->offset = _jit->pc.w;
|
|
#endif
|
|
value = jit_classify(node->code);
|
|
jit_regarg_set(node, value);
|
|
switch (node->code) {
|
|
case jit_code_align:
|
|
assert(!(node->u.w & (node->u.w - 1)) &&
|
|
node->u.w <= sizeof(jit_word_t));
|
|
if (node->u.w == sizeof(jit_word_t) &&
|
|
(word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
|
|
nop(sizeof(jit_word_t) - word);
|
|
break;
|
|
case jit_code_note: case jit_code_name:
|
|
node->u.w = _jit->pc.w;
|
|
break;
|
|
case jit_code_label:
|
|
if ((node->link || (node->flag & jit_flag_use)) &&
|
|
(word = _jit->pc.w & 3))
|
|
nop(4 - word);
|
|
/* remember label is defined */
|
|
node->flag |= jit_flag_patch;
|
|
node->u.w = _jit->pc.w;
|
|
break;
|
|
case_rrr(add,);
|
|
case_rrw(add,);
|
|
case_rrr(addc,);
|
|
case_rrw(addc,);
|
|
case_rrr(addx,);
|
|
case_rrw(addx,);
|
|
case_rrr(sub,);
|
|
case_rrw(sub,);
|
|
case_rrr(subc,);
|
|
case_rrw(subc,);
|
|
case_rrr(subx,);
|
|
case_rrw(subx,);
|
|
case_rrw(rsb,);
|
|
case_rrr(mul,);
|
|
case_rrw(mul,);
|
|
case_rrrr(qmul,);
|
|
case_rrrw(qmul,);
|
|
case_rrrr(qmul, _u);
|
|
case_rrrw(qmul, _u);
|
|
case_rrr(div,);
|
|
case_rrw(div,);
|
|
case_rrr(div, _u);
|
|
case_rrw(div, _u);
|
|
case_rrr(rem,);
|
|
case_rrw(rem,);
|
|
case_rrr(rem, _u);
|
|
case_rrw(rem, _u);
|
|
case_rrrr(qdiv,);
|
|
case_rrrw(qdiv,);
|
|
case_rrrr(qdiv, _u);
|
|
case_rrrw(qdiv, _u);
|
|
case_rrr(lsh,);
|
|
case_rrw(lsh,);
|
|
case_rrr(rsh,);
|
|
case_rrw(rsh,);
|
|
case_rrr(rsh, _u);
|
|
case_rrw(rsh, _u);
|
|
case_rr(neg,);
|
|
case_rr(com,);
|
|
case_rrr(and,);
|
|
case_rrw(and,);
|
|
case_rrr(or,);
|
|
case_rrw(or,);
|
|
case_rrr(xor,);
|
|
case_rrw(xor,);
|
|
case_rr(trunc, _f_i);
|
|
case_rr(trunc, _d_i);
|
|
#if __WORDSIZE == 64
|
|
case_rr(trunc, _f_l);
|
|
case_rr(trunc, _d_l);
|
|
#endif
|
|
case_rr(ld, _c);
|
|
case_rw(ld, _c);
|
|
case_rr(ld, _uc);
|
|
case_rw(ld, _uc);
|
|
case_rr(ld, _s);
|
|
case_rw(ld, _s);
|
|
case_rr(ld, _us);
|
|
case_rw(ld, _us);
|
|
case_rr(ld, _i);
|
|
case_rw(ld, _i);
|
|
#if __WORDSIZE == 64
|
|
case_rr(ld, _ui);
|
|
case_rw(ld, _ui);
|
|
case_rr(ld, _l);
|
|
case_rw(ld, _l);
|
|
#endif
|
|
case_rrr(ldx, _c);
|
|
case_rrw(ldx, _c);
|
|
case_rrr(ldx, _uc);
|
|
case_rrw(ldx, _uc);
|
|
case_rrr(ldx, _s);
|
|
case_rrw(ldx, _s);
|
|
case_rrr(ldx, _us);
|
|
case_rrw(ldx, _us);
|
|
case_rrr(ldx, _i);
|
|
case_rrw(ldx, _i);
|
|
#if __WORDSIZE == 64
|
|
case_rrr(ldx, _ui);
|
|
case_rrw(ldx, _ui);
|
|
case_rrr(ldx, _l);
|
|
case_rrw(ldx, _l);
|
|
#endif
|
|
case_rr(st, _c);
|
|
case_wr(st, _c);
|
|
case_rr(st, _s);
|
|
case_wr(st, _s);
|
|
case_rr(st, _i);
|
|
case_wr(st, _i);
|
|
#if __WORDSIZE == 64
|
|
case_rr(st, _l);
|
|
case_wr(st, _l);
|
|
#endif
|
|
case_rrr(stx, _c);
|
|
case_wrr(stx, _c);
|
|
case_rrr(stx, _s);
|
|
case_wrr(stx, _s);
|
|
case_rrr(stx, _i);
|
|
case_wrr(stx, _i);
|
|
#if __WORDSIZE == 64
|
|
case_rrr(stx, _l);
|
|
case_wrr(stx, _l);
|
|
#endif
|
|
case_rr(hton, _us);
|
|
case_rr(hton, _ui);
|
|
#if __WORDSIZE == 64
|
|
case_rr(hton, _ul);
|
|
#endif
|
|
case_rr(ext, _c);
|
|
case_rr(ext, _uc);
|
|
case_rr(ext, _s);
|
|
case_rr(ext, _us);
|
|
#if __WORDSIZE == 64
|
|
case_rr(ext, _i);
|
|
case_rr(ext, _ui);
|
|
#endif
|
|
case_rr(mov,);
|
|
case jit_code_movi:
|
|
if (node->flag & jit_flag_node) {
|
|
temp = node->v.n;
|
|
if (temp->code == jit_code_data ||
|
|
(temp->code == jit_code_label &&
|
|
(temp->flag & jit_flag_patch)))
|
|
movi(rn(node->u.w), temp->u.w);
|
|
else {
|
|
assert(temp->code == jit_code_label ||
|
|
temp->code == jit_code_epilog);
|
|
word = movi_p(rn(node->u.w), temp->u.w);
|
|
patch(word, node);
|
|
}
|
|
}
|
|
else
|
|
movi(rn(node->u.w), node->v.w);
|
|
break;
|
|
case_rrr(lt,);
|
|
case_rrw(lt,);
|
|
case_rrr(lt, _u);
|
|
case_rrw(lt, _u);
|
|
case_rrr(le,);
|
|
case_rrw(le,);
|
|
case_rrr(le, _u);
|
|
case_rrw(le, _u);
|
|
case_rrr(eq,);
|
|
case_rrw(eq,);
|
|
case_rrr(ge,);
|
|
case_rrw(ge,);
|
|
case_rrr(ge, _u);
|
|
case_rrw(ge, _u);
|
|
case_rrr(gt,);
|
|
case_rrw(gt,);
|
|
case_rrr(gt, _u);
|
|
case_rrw(gt, _u);
|
|
case_rrr(ne,);
|
|
case_rrw(ne,);
|
|
case_brr(blt,);
|
|
case_brw(blt,);
|
|
case_brr(blt, _u);
|
|
case_brw(blt, _u);
|
|
case_brr(ble,);
|
|
case_brw(ble,);
|
|
case_brr(ble, _u);
|
|
case_brw(ble, _u);
|
|
case_brr(beq,);
|
|
case_brw(beq,);
|
|
case_brr(bge,);
|
|
case_brw(bge,);
|
|
case_brr(bge, _u);
|
|
case_brw(bge, _u);
|
|
case_brr(bgt,);
|
|
case_brw(bgt,);
|
|
case_brr(bgt, _u);
|
|
case_brw(bgt, _u);
|
|
case_brr(bne,);
|
|
case_brw(bne,);
|
|
case_brr(boadd,);
|
|
case_brw(boadd,);
|
|
case_brr(boadd, _u);
|
|
case_brw(boadd, _u);
|
|
case_brr(bxadd,);
|
|
case_brw(bxadd,);
|
|
case_brr(bxadd, _u);
|
|
case_brw(bxadd, _u);
|
|
case_brr(bosub,);
|
|
case_brw(bosub,);
|
|
case_brr(bosub, _u);
|
|
case_brw(bosub, _u);
|
|
case_brr(bxsub,);
|
|
case_brw(bxsub,);
|
|
case_brr(bxsub, _u);
|
|
case_brw(bxsub, _u);
|
|
case_brr(bms,);
|
|
case_brw(bms,);
|
|
case_brr(bmc,);
|
|
case_brw(bmc,);
|
|
case_rrr(add, _f);
|
|
case_rrf(add);
|
|
case_rrr(sub, _f);
|
|
case_rrf(sub);
|
|
case_rrf(rsb);
|
|
case_rrr(mul, _f);
|
|
case_rrf(mul);
|
|
case_rrr(div, _f);
|
|
case_rrf(div);
|
|
case_rr(abs, _f);
|
|
case_rr(neg, _f);
|
|
case_rr(sqrt, _f);
|
|
case_rr(ext, _f);
|
|
case_rr(ld, _f);
|
|
case_rw(ld, _f);
|
|
case_rrr(ldx, _f);
|
|
case_rrw(ldx, _f);
|
|
case_rr(st, _f);
|
|
case_wr(st, _f);
|
|
case_rrr(stx, _f);
|
|
case_wrr(stx, _f);
|
|
case_rr(mov, _f);
|
|
case jit_code_movi_f:
|
|
assert_data(node);
|
|
movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
|
|
break;
|
|
case_rr(ext, _d_f);
|
|
case_rrr(lt, _f);
|
|
case_rrf(lt);
|
|
case_rrr(le, _f);
|
|
case_rrf(le);
|
|
case_rrr(eq, _f);
|
|
case_rrf(eq);
|
|
case_rrr(ge, _f);
|
|
case_rrf(ge);
|
|
case_rrr(gt, _f);
|
|
case_rrf(gt);
|
|
case_rrr(ne, _f);
|
|
case_rrf(ne);
|
|
case_rrr(unlt, _f);
|
|
case_rrf(unlt);
|
|
case_rrr(unle, _f);
|
|
case_rrf(unle);
|
|
case_rrr(uneq, _f);
|
|
case_rrf(uneq);
|
|
case_rrr(unge, _f);
|
|
case_rrf(unge);
|
|
case_rrr(ungt, _f);
|
|
case_rrf(ungt);
|
|
case_rrr(ltgt, _f);
|
|
case_rrf(ltgt);
|
|
case_rrr(ord, _f);
|
|
case_rrf(ord);
|
|
case_rrr(unord, _f);
|
|
case_rrf(unord);
|
|
case_brr(blt, _f);
|
|
case_brf(blt);
|
|
case_brr(ble, _f);
|
|
case_brf(ble);
|
|
case_brr(beq, _f);
|
|
case_brf(beq);
|
|
case_brr(bge, _f);
|
|
case_brf(bge);
|
|
case_brr(bgt, _f);
|
|
case_brf(bgt);
|
|
case_brr(bne, _f);
|
|
case_brf(bne);
|
|
case_brr(bunlt, _f);
|
|
case_brf(bunlt);
|
|
case_brr(bunle, _f);
|
|
case_brf(bunle);
|
|
case_brr(buneq, _f);
|
|
case_brf(buneq);
|
|
case_brr(bunge, _f);
|
|
case_brf(bunge);
|
|
case_brr(bungt, _f);
|
|
case_brf(bungt);
|
|
case_brr(bltgt, _f);
|
|
case_brf(bltgt);
|
|
case_brr(bord, _f);
|
|
case_brf(bord);
|
|
case_brr(bunord, _f);
|
|
case_brf(bunord);
|
|
case_rrr(add, _d);
|
|
case_rrd(add);
|
|
case_rrr(sub, _d);
|
|
case_rrd(sub);
|
|
case_rrd(rsb);
|
|
case_rrr(mul, _d);
|
|
case_rrd(mul);
|
|
case_rrr(div, _d);
|
|
case_rrd(div);
|
|
case_rr(abs, _d);
|
|
case_rr(neg, _d);
|
|
case_rr(sqrt, _d);
|
|
case_rr(ext, _d);
|
|
case_rr(ld, _d);
|
|
case_rw(ld, _d);
|
|
case_rrr(ldx, _d);
|
|
case_rrw(ldx, _d);
|
|
case_rr(st, _d);
|
|
case_wr(st, _d);
|
|
case_rrr(stx, _d);
|
|
case_wrr(stx, _d);
|
|
case_rr(mov, _d);
|
|
case jit_code_movi_d:
|
|
assert_data(node);
|
|
movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
|
|
break;
|
|
case_rr(ext, _f_d);
|
|
case_rrr(lt, _d);
|
|
case_rrd(lt);
|
|
case_rrr(le, _d);
|
|
case_rrd(le);
|
|
case_rrr(eq, _d);
|
|
case_rrd(eq);
|
|
case_rrr(ge, _d);
|
|
case_rrd(ge);
|
|
case_rrr(gt, _d);
|
|
case_rrd(gt);
|
|
case_rrr(ne, _d);
|
|
case_rrd(ne);
|
|
case_rrr(unlt, _d);
|
|
case_rrd(unlt);
|
|
case_rrr(unle, _d);
|
|
case_rrd(unle);
|
|
case_rrr(uneq, _d);
|
|
case_rrd(uneq);
|
|
case_rrr(unge, _d);
|
|
case_rrd(unge);
|
|
case_rrr(ungt, _d);
|
|
case_rrd(ungt);
|
|
case_rrr(ltgt, _d);
|
|
case_rrd(ltgt);
|
|
case_rrr(ord, _d);
|
|
case_rrd(ord);
|
|
case_rrr(unord, _d);
|
|
case_rrd(unord);
|
|
case_brr(blt, _d);
|
|
case_brd(blt);
|
|
case_brr(ble, _d);
|
|
case_brd(ble);
|
|
case_brr(beq, _d);
|
|
case_brd(beq);
|
|
case_brr(bge, _d);
|
|
case_brd(bge);
|
|
case_brr(bgt, _d);
|
|
case_brd(bgt);
|
|
case_brr(bne, _d);
|
|
case_brd(bne);
|
|
case_brr(bunlt, _d);
|
|
case_brd(bunlt);
|
|
case_brr(bunle, _d);
|
|
case_brd(bunle);
|
|
case_brr(buneq, _d);
|
|
case_brd(buneq);
|
|
case_brr(bunge, _d);
|
|
case_brd(bunge);
|
|
case_brr(bungt, _d);
|
|
case_brd(bungt);
|
|
case_brr(bltgt, _d);
|
|
case_brd(bltgt);
|
|
case_brr(bord, _d);
|
|
case_brd(bord);
|
|
case_brr(bunord, _d);
|
|
case_brd(bunord);
|
|
case jit_code_jmpr:
|
|
jmpr(rn(node->u.w));
|
|
break;
|
|
case jit_code_jmpi:
|
|
if (node->flag & jit_flag_node) {
|
|
temp = node->u.n;
|
|
assert(temp->code == jit_code_label ||
|
|
temp->code == jit_code_epilog);
|
|
if (temp->flag & jit_flag_patch)
|
|
jmpi(temp->u.w);
|
|
else {
|
|
word = jmpi_p(_jit->pc.w);
|
|
patch(word, node);
|
|
}
|
|
}
|
|
else
|
|
jmpi(node->u.w);
|
|
break;
|
|
case jit_code_callr:
|
|
callr(rn(node->u.w));
|
|
break;
|
|
case jit_code_calli:
|
|
if (node->flag & jit_flag_node) {
|
|
temp = node->u.n;
|
|
assert(temp->code == jit_code_label ||
|
|
temp->code == jit_code_epilog);
|
|
if (temp->flag & jit_flag_patch)
|
|
calli(temp->u.w);
|
|
else {
|
|
word = calli_p(_jit->pc.w);
|
|
patch(word, node);
|
|
}
|
|
}
|
|
else
|
|
calli(node->u.w);
|
|
break;
|
|
case jit_code_prolog:
|
|
_jitc->function = _jitc->functions.ptr + node->w.w;
|
|
undo.node = node;
|
|
undo.word = _jit->pc.w;
|
|
undo.patch_offset = _jitc->patches.offset;
|
|
restart_function:
|
|
_jitc->again = 0;
|
|
prolog(node);
|
|
break;
|
|
case jit_code_epilog:
|
|
assert(_jitc->function == _jitc->functions.ptr + node->w.w);
|
|
if (_jitc->again) {
|
|
for (temp = undo.node->next;
|
|
temp != node; temp = temp->next) {
|
|
if (temp->code == jit_code_label ||
|
|
temp->code == jit_code_epilog)
|
|
temp->flag &= ~jit_flag_patch;
|
|
}
|
|
temp->flag &= ~jit_flag_patch;
|
|
node = undo.node;
|
|
_jit->pc.w = undo.word;
|
|
_jitc->patches.offset = undo.patch_offset;
|
|
goto restart_function;
|
|
}
|
|
if (node->link && (word = _jit->pc.w & 3))
|
|
nop(4 - word);
|
|
/* remember label is defined */
|
|
node->flag |= jit_flag_patch;
|
|
node->u.w = _jit->pc.w;
|
|
epilog(node);
|
|
_jitc->function = NULL;
|
|
break;
|
|
case jit_code_live:
|
|
case jit_code_arg:
|
|
case jit_code_arg_f: case jit_code_arg_d:
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
jit_regarg_clr(node, value);
|
|
assert(_jitc->regarg == 0);
|
|
/* update register live state */
|
|
jit_reglive(node);
|
|
}
|
|
#undef case_brw
|
|
#undef case_brr
|
|
#undef case_wrr
|
|
#undef case_rrw
|
|
#undef case_rrr
|
|
#undef case_wr
|
|
#undef case_rw
|
|
#undef case_rr
|
|
|
|
for (offset = 0; offset < _jitc->patches.offset; offset++) {
|
|
node = _jitc->patches.ptr[offset].node;
|
|
word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
|
|
patch_at(_jitc->patches.ptr[offset].inst, word);
|
|
}
|
|
|
|
jit_flush(_jit->code.ptr, _jit->pc.uc);
|
|
|
|
return (_jit->code.ptr);
|
|
}
|
|
|
|
#define CODE 1
|
|
# include "jit_s390-cpu.c"
|
|
# include "jit_s390-fpu.c"
|
|
#undef CODE
|
|
|
|
void
|
|
jit_flush(void *fptr, void *tptr)
|
|
{
|
|
#if defined(__GNUC__)
|
|
jit_word_t f, t, s;
|
|
|
|
s = sysconf(_SC_PAGE_SIZE);
|
|
f = (jit_word_t)fptr & -s;
|
|
t = (((jit_word_t)tptr) + s - 1) & -s;
|
|
__clear_cache((void *)f, (void *)t);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
_emit_ldxi(jit_state_t *_jit, jit_gpr_t r0, jit_gpr_t r1, jit_word_t i0)
|
|
{
|
|
ldxi(rn(r0), rn(r1), i0);
|
|
}
|
|
|
|
void
|
|
_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_gpr_t r1)
|
|
{
|
|
stxi(i0, rn(r0), rn(r1));
|
|
}
|
|
|
|
void
|
|
_emit_ldxi_d(jit_state_t *_jit, jit_fpr_t r0, jit_gpr_t r1, jit_word_t i0)
|
|
{
|
|
ldxi_d(rn(r0), rn(r1), i0);
|
|
}
|
|
|
|
void
|
|
_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_fpr_t r1)
|
|
{
|
|
stxi_d(i0, rn(r0), rn(r1));
|
|
}
|
|
|
|
static jit_int32_t
|
|
_jit_get_reg_pair(jit_state_t *_jit)
|
|
{
|
|
jit_int32_t r1, r2;
|
|
/* Try to find a register pair for use with operations that
|
|
* require a odd based register pair. Search for the best
|
|
* match to avoid spills or at least a valid operation.
|
|
*/
|
|
|
|
/* Try non callee save first */
|
|
if (jit_reg_free_p(_R0) && jit_reg_free_p(_R1))
|
|
r1 = _R0, r2 = _R1;
|
|
else if (jit_reg_free_p(_R2) && jit_reg_free_p(_R3))
|
|
r1 = _R2, r2 = _R3;
|
|
else if (jit_reg_free_p(_R4) && jit_reg_free_p(_R5))
|
|
r1 = _R4, r2 = _R5;
|
|
/* Try callee save registers */
|
|
else if (jit_reg_free_p(_R10) && jit_reg_free_p(_R11))
|
|
r1 = _R10, r2 = _R11;
|
|
else if (jit_reg_free_p(_R8) && jit_reg_free_p(_R9))
|
|
r1 = _R8, r2 = _R9;
|
|
else if (jit_reg_free_p(_R6) && jit_reg_free_p(_R7))
|
|
r1 = _R6, r2 = _R7;
|
|
|
|
/* We *must* find a register pair */
|
|
else if (jit_reg_free_if_spill_p(_R0) && jit_reg_free_if_spill_p(_R1))
|
|
r1 = _R0, r2 = _R1;
|
|
else if (jit_reg_free_if_spill_p(_R2) && jit_reg_free_if_spill_p(_R3))
|
|
r1 = _R2, r2 = _R3;
|
|
else if (jit_reg_free_if_spill_p(_R4) && jit_reg_free_if_spill_p(_R5))
|
|
r1 = _R4, r2 = _R5;
|
|
else if (jit_reg_free_if_spill_p(_R10) && jit_reg_free_if_spill_p(_R11))
|
|
r1 = _R10, r2 = _R11;
|
|
else if (jit_reg_free_if_spill_p(_R8) && jit_reg_free_if_spill_p(_R9))
|
|
r1 = _R8, r2 = _R9;
|
|
else if (jit_reg_free_if_spill_p(_R6) && jit_reg_free_if_spill_p(_R7))
|
|
r1 = _R6, r2 = _R7;
|
|
else
|
|
/* Do not jit_get_reg() all registers to avoid it */
|
|
abort();
|
|
|
|
(void)jit_get_reg(jit_class_gpr|jit_class_named|r1);
|
|
(void)jit_get_reg(jit_class_gpr|jit_class_named|r2);
|
|
|
|
return (r1);
|
|
}
|
|
|
|
static void
|
|
_jit_unget_reg_pair(jit_state_t *_jit, jit_int32_t reg)
|
|
{
|
|
jit_int32_t r1, r2;
|
|
r1 = reg;
|
|
switch (r1) {
|
|
case _R0: r2 = _R1; break;
|
|
case _R2: r2 = _R3; break;
|
|
case _R4: r2 = _R5; break;
|
|
case _R6: r2 = _R7; break;
|
|
case _R8: r2 = _R9; break;
|
|
case _R10: r2 = _R11; break;
|
|
default: abort();
|
|
}
|
|
jit_unget_reg(r1);
|
|
jit_unget_reg(r2);
|
|
}
|
|
|
|
static jit_int32_t
|
|
_jit_get_reg_but_zero(jit_state_t *_jit, jit_int32_t flags)
|
|
{
|
|
jit_int32_t reg;
|
|
reg = jit_get_reg(jit_class_gpr);
|
|
if (reg == _R0) {
|
|
reg = jit_get_reg(jit_class_gpr|flags);
|
|
jit_unget_reg(_R0);
|
|
}
|
|
return (reg);
|
|
}
|
|
|
|
static void
|
|
_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
|
|
{
|
|
jit_int32_t flag;
|
|
|
|
assert(node->flag & jit_flag_node);
|
|
if (node->code == jit_code_movi)
|
|
flag = node->v.n->flag;
|
|
else
|
|
flag = node->u.n->flag;
|
|
assert(!(flag & jit_flag_patch));
|
|
if (_jitc->patches.offset >= _jitc->patches.length) {
|
|
jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
|
|
_jitc->patches.length * sizeof(jit_patch_t),
|
|
(_jitc->patches.length + 1024) * sizeof(jit_patch_t));
|
|
_jitc->patches.length += 1024;
|
|
}
|
|
_jitc->patches.ptr[_jitc->patches.offset].inst = instr;
|
|
_jitc->patches.ptr[_jitc->patches.offset].node = node;
|
|
++_jitc->patches.offset;
|
|
}
|