1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-29 19:30:36 +02:00

Merge remote-tracking branch 'lightening/master'

This commit is contained in:
Andy Wingo 2019-05-20 15:48:27 +02:00
commit e057ea01f6
20 changed files with 7811 additions and 15823 deletions

View file

@ -1,12 +1,16 @@
# use the official gcc image, based on debian
# can use verions as well, like gcc:5.2
# see https://hub.docker.com/_/gcc/
image: debian
image: debian:testing
before_script:
- dpkg --add-architecture i386
- dpkg --add-architecture arm64
- dpkg --add-architecture armhf
- apt-get update -qq
- apt-get install -y libc6-dev:amd64 libc6-dev:i386 gcc gcc-multilib make
- apt-get install -y
libc6-dev:amd64 gcc make
qemu binfmt-support qemu-user-static
gcc-i686-linux-gnu libc6-dev-i386-cross libc6:i386
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6:arm64
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6:armhf
x86-64:
stage: test
@ -16,4 +20,14 @@ x86-64:
i686:
stage: test
script:
- make -C tests test-ia32
- make -C tests test-ia32 CC_IA32=i686-linux-gnu-gcc
aarch64:
stage: test
script:
- make -C tests test-aarch64 CC_AARCH64=aarch64-linux-gnu-gcc
armhf:
stage: test
script:
- make -C tests test-armv7 CC_ARMv7=arm-linux-gnueabihf-gcc

View file

@ -28,10 +28,30 @@ Guile needs a simple, light-weight code generation library. The GNU
Lightning architecture-specific backends provide the bulk of this
functionality, and Lightening wraps it all in a lightweight API.
## Supported targets
Lightening can generate code for the x86-64, i686, ARMv7, and AArch64
architectures. It supports the calling conventions of MS Windows,
GNU/Linux, and Mac OS.
On i686, Lightening requires SSE support. On ARMv7, we require hardware
floating-point support (the VFP instructions), as well as the UDIV/SDIV
instructions.
Lightening is automatically tested using GitLab's continuous integration
for under the supported architectures, for GNU/Linux; for a list of
recent jobs, see [the CI
page](https://gitlab.com/wingo/lightening/-/jobs).
## Future targets
Lightening has some inherited code from GNU Lightning for MIPS, PPC64,
and s390. Patches to adapt this code to the Lightening code structure
are quite welcome.
RISC-V support would be fun too.
## Status
Only the x86-64 port is currently usable. I plan to re-enable 32-bit
x86 shortly, and then work on 32-bit and 64-bit ARM. Other
architectures may come with time, but help is very much appreciated
there. The test suite is still in progress but will be fairly
comprehensive in terms of API surface.
Lightening is used in GNU Guile since version 2.9.2 and seems to work
well.

View file

@ -65,28 +65,6 @@ jit_same_fprs (jit_fpr_t a, jit_fpr_t b)
return jit_fpr_regno (a) == jit_fpr_regno (b);
}
enum jit_reloc_kind
{
JIT_RELOC_ABSOLUTE,
JIT_RELOC_REL8,
JIT_RELOC_REL16,
JIT_RELOC_REL32,
JIT_RELOC_REL64,
};
typedef struct jit_reloc
{
uint8_t kind;
uint8_t inst_start_offset;
uint32_t offset;
} jit_reloc_t;
#if defined(__GNUC__) && (__GNUC__ >= 4)
# define JIT_API extern __attribute__ ((__visibility__("hidden")))
#else
# define JIT_API extern
#endif
#if defined(__i386__) || defined(__x86_64__)
# include "lightening/x86.h"
#elif defined(__mips__)
@ -101,6 +79,35 @@ typedef struct jit_reloc
# include "lightening/s390.h"
#endif
enum jit_reloc_kind
{
JIT_RELOC_ABSOLUTE,
JIT_RELOC_REL8,
JIT_RELOC_REL16,
JIT_RELOC_REL32,
JIT_RELOC_REL64,
#ifdef JIT_NEEDS_LITERAL_POOL
JIT_RELOC_JMP_WITH_VENEER,
JIT_RELOC_JCC_WITH_VENEER,
JIT_RELOC_LOAD_FROM_POOL,
#endif
};
typedef struct jit_reloc
{
uint8_t kind;
uint8_t inst_start_offset;
uint8_t pc_base_offset;
uint8_t rsh;
uint32_t offset;
} jit_reloc_t;
#if defined(__GNUC__) && (__GNUC__ >= 4)
# define JIT_API extern __attribute__ ((__visibility__("hidden")))
#else
# define JIT_API extern
#endif
typedef struct jit_state jit_state_t;
enum jit_operand_abi
@ -567,17 +574,10 @@ jit_load_args_3(jit_state_t *_jit, jit_operand_t a, jit_operand_t b,
M(RGG__, bxsubr_u) \
M(RGu__, bxsubi_u) \
\
M(_i___, nop) \
\
M(_G___, jmpr) \
M(_p___, jmpi) \
M(R____, jmp) \
\
M(_G___, pushr) \
M(_F___, pushr_d) \
M(_G___, popr) \
M(_F___, popr_d) \
\
M(_____, ret) \
M(_G___, retr) \
M(_F___, retr_f) \

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2017 Free Software Foundation, Inc.
* Copyright (C) 2013-2017, 2019 Free Software Foundation, Inc.
*
* This file is part of GNU lightning.
*
@ -20,70 +20,148 @@
#ifndef _jit_aarch64_h
#define _jit_aarch64_h
#define JIT_HASH_CONSTS 0
#define JIT_NUM_OPERANDS 3
/*
* Types
*/
#define JIT_FP _R29
typedef enum {
#define jit_r(i) (_R9 + (i))
#define jit_r_num() 7
#define jit_v(i) (_R19 + (i))
#define jit_v_num() 10
#define jit_f(i) (_V8 + (i))
#define jit_f_num() 8
#define JIT_R0 _R9
#define JIT_R1 _R10
#define JIT_R2 _R11
#define JIT_R3 _R12
#define JIT_R4 _R13
#define JIT_R5 _R14
#define JIT_R6 _R15
_R8, /* indirect result */
_R18, /* platform register */
_R17, /* IP1 */
_R16, /* IP0 */
_R9, _R10, _R11, _R12, /* temporaries */
_R13, _R14, _R15,
#define JIT_V0 _R19
#define JIT_V1 _R20
#define JIT_V2 _R21
#define JIT_V3 _R22
#define JIT_V4 _R23
#define JIT_V5 _R24
#define JIT_V6 _R25
#define JIT_V7 _R26
#define JIT_V8 _R27
#define JIT_V9 _R28
_R19, _R20, _R21, _R22, /* callee save */
_R23, _R24, _R25, _R26,
_R27, _R28,
_SP, /* stack pointer */
_R30, /* link register */
_R29, /* frame pointer */
_R7, _R6, _R5, _R4,
_R3, _R2, _R1, _R0,
#define JIT_F0 _V8
#define JIT_F1 _V9
#define JIT_F2 _V10
#define JIT_F3 _V11
#define JIT_F4 _V12
#define JIT_F5 _V13
#define JIT_F6 _V14
#define JIT_F7 _V15
_V31, _V30, _V29, _V28, /* temporaries */
_V27, _V26, _V25, _V24,
_V23, _V22, _V21, _V20,
_V19, _V18, _V17, _V16,
/* callee save */
_V8, _V9, _V10, _V11,
_V12, _V13, _V14, _V15,
_V7, _V6, _V5, _V4, /* arguments */
_V3, _V2, _V1, _V0,
_NOREG,
#define JIT_NOREG _NOREG
} jit_reg_t;
#define JIT_NEEDS_LITERAL_POOL 1
#define _X0 JIT_GPR(0)
#define _X1 JIT_GPR(1)
#define _X2 JIT_GPR(2)
#define _X3 JIT_GPR(3)
#define _X4 JIT_GPR(4)
#define _X5 JIT_GPR(5)
#define _X6 JIT_GPR(6)
#define _X7 JIT_GPR(7)
#define _X8 JIT_GPR(8)
#define _X9 JIT_GPR(9)
#define _X10 JIT_GPR(10)
#define _X11 JIT_GPR(11)
#define _X12 JIT_GPR(12)
#define _X13 JIT_GPR(13)
#define _X14 JIT_GPR(14)
#define _X15 JIT_GPR(15)
#define _X16 JIT_GPR(16)
#define _X17 JIT_GPR(17)
#define _X18 JIT_GPR(18)
#define _X19 JIT_GPR(19)
#define _X20 JIT_GPR(20)
#define _X21 JIT_GPR(21)
#define _X22 JIT_GPR(22)
#define _X23 JIT_GPR(23)
#define _X24 JIT_GPR(24)
#define _X25 JIT_GPR(25)
#define _X26 JIT_GPR(26)
#define _X27 JIT_GPR(27)
#define _X28 JIT_GPR(28)
#define _X29 JIT_GPR(29)
#define _X30 JIT_GPR(30)
#define _X31 JIT_GPR(31)
#define _D0 JIT_FPR(0)
#define _D1 JIT_FPR(1)
#define _D2 JIT_FPR(2)
#define _D3 JIT_FPR(3)
#define _D4 JIT_FPR(4)
#define _D5 JIT_FPR(5)
#define _D6 JIT_FPR(6)
#define _D7 JIT_FPR(7)
#define _D8 JIT_FPR(8)
#define _D9 JIT_FPR(9)
#define _D10 JIT_FPR(10)
#define _D11 JIT_FPR(11)
#define _D12 JIT_FPR(12)
#define _D13 JIT_FPR(13)
#define _D14 JIT_FPR(14)
#define _D15 JIT_FPR(15)
#define _D16 JIT_FPR(16)
#define _D17 JIT_FPR(17)
#define _D18 JIT_FPR(18)
#define _D19 JIT_FPR(19)
#define _D20 JIT_FPR(20)
#define _D21 JIT_FPR(21)
#define _D22 JIT_FPR(22)
#define _D23 JIT_FPR(23)
#define _D24 JIT_FPR(24)
#define _D25 JIT_FPR(25)
#define _D26 JIT_FPR(26)
#define _D27 JIT_FPR(27)
#define _D28 JIT_FPR(28)
#define _D29 JIT_FPR(29)
#define _D30 JIT_FPR(30)
#define _D31 JIT_FPR(31)
#define JIT_R0 _X0
#define JIT_R1 _X1
#define JIT_R2 _X2
#define JIT_R3 _X3
#define JIT_R4 _X4
#define JIT_R5 _X5
#define JIT_R6 _X6
#define JIT_R7 _X7
#define JIT_R8 _X8
#define JIT_R9 _X9
#define JIT_R10 _X10
#define JIT_R11 _X11
#define JIT_R12 _X12
#define JIT_R13 _X13
#define JIT_R14 _X14
#define JIT_R15 _X15
#define JIT_R16 _X16
#define JIT_TMP0 _X17
#define JIT_TMP1 _X18
#define JIT_V0 _X19
#define JIT_V1 _X20
#define JIT_V2 _X21
#define JIT_V3 _X22
#define JIT_V4 _X23
#define JIT_V5 _X24
#define JIT_V6 _X25
#define JIT_V7 _X26
#define JIT_V8 _X27
#define JIT_V9 _X28
// x29 is frame pointer; x30 is link register.
#define JIT_PLATFORM_CALLEE_SAVE_GPRS _X29, _X30
// x31 is stack pointer.
#define JIT_SP _X31
#define JIT_F0 _D0
#define JIT_F1 _D1
#define JIT_F2 _D2
#define JIT_F3 _D3
#define JIT_F4 _D4
#define JIT_F5 _D5
#define JIT_F6 _D6
#define JIT_F7 _D7
#define JIT_F8 _D16
#define JIT_F9 _D17
#define JIT_F10 _D18
#define JIT_F11 _D19
#define JIT_F12 _D20
#define JIT_F13 _D21
#define JIT_F14 _D22
#define JIT_F15 _D23
#define JIT_F16 _D24
#define JIT_F17 _D25
#define JIT_F18 _D26
#define JIT_F19 _D27
#define JIT_F20 _D28
#define JIT_F21 _D29
#define JIT_F22 _D30
#define JIT_FTMP _D31
#define JIT_VF0 _D8
#define JIT_VF1 _D9
#define JIT_VF2 _D10
#define JIT_VF3 _D11
#define JIT_VF4 _D12
#define JIT_VF5 _D13
#define JIT_VF6 _D14
#define JIT_VF7 _D15
#define _FP _X29
#define _LR _X30
#define _SP _X31
#endif /* _jit_aarch64_h */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012-2018 Free Software Foundation, Inc.
* Copyright (C) 2012-2019 Free Software Foundation, Inc.
*
* This file is part of GNU lightning.
*
@ -20,108 +20,114 @@
#ifndef _jit_arm_h
#define _jit_arm_h
#define JIT_HASH_CONSTS 0
#define JIT_NUM_OPERANDS 3
/*
* Types
*/
#define jit_swf_p() (jit_cpu.vfp == 0)
#define jit_hardfp_p() jit_cpu.abi
#define jit_ldrt_strt_p() jit_cpu.ldrt_strt
#define JIT_NEEDS_LITERAL_POOL 1
#define JIT_FP _R11
typedef enum {
#define jit_r(i) (_R4 + (i))
#define jit_r_num() 3
#define jit_v(i) (_R7 + (i))
#define jit_v_num() 3
#define jit_f(i) (jit_cpu.abi ? _D8 + ((i)<<1) : _D0 - ((i)<<1))
#define jit_f_num() 8
_R12, /* ip - temporary */
#define JIT_R0 _R4
#define JIT_R1 _R5
#define JIT_R2 _R6
_R4, /* r4 - variable */
_R5, /* r5 - variable */
_R6, /* r6 - variable */
#define JIT_V0 _R7
#define JIT_V1 _R8
#define JIT_V2 _R9
_R7, /* r7 - variable */
_R8, /* r8 - variable */
_R9, /* r9 - variable */
_R10, /* sl - stack limit */
_R11, /* fp - frame pointer */
_R13, /* sp - stack pointer */
_R14, /* lr - link register */
_R15, /* pc - program counter */
_R3, /* r3 - argument/result */
_R2, /* r2 - argument/result */
_R1, /* r1 - argument/result */
_R0, /* r0 - argument/result */
#define JIT_F0 (jit_hardfp_p() ? _D8 : _D0)
#define JIT_F1 (jit_hardfp_p() ? _D9 : _D1)
#define JIT_F2 (jit_hardfp_p() ? _D10 : _D2)
#define JIT_F3 (jit_hardfp_p() ? _D11 : _D3)
#define JIT_F4 (jit_hardfp_p() ? _D12 : _D4)
#define JIT_F5 (jit_hardfp_p() ? _D13 : _D5)
#define JIT_F6 (jit_hardfp_p() ? _D14 : _D6)
#define JIT_F7 (jit_hardfp_p() ? _D15 : _D7)
_S16, _D8 = _S16, _Q4 = _D8,
_S17,
_S18, _D9 = _S18,
_S19,
_S20, _D10 = _S20, _Q5 = _D10,
_S21,
_S22, _D11 = _S22,
_S23,
_S24, _D12 = _S24, _Q6 = _D12,
_S25,
_S26, _D13 = _S26,
_S27,
_S28, _D14 = _S28, _Q7 = _D14,
_S29,
_S30, _D15 = _S30,
_S31,
_S15,
_S14, _D7 = _S14,
_S13,
_S12, _D6 = _S12, _Q3 = _D6,
_S11,
_S10, _D5 = _S10,
_S9,
_S8, _D4 = _S8, _Q2 = _D4,
_S7,
_S6, _D3 = _S6,
_S5,
_S4, _D2 = _S4, _Q1 = _D2,
_S3,
_S2, _D1 = _S2,
_S1,
_S0, _D0 = _S0, _Q0 = _D0,
_NOREG,
#define JIT_NOREG _NOREG
} jit_reg_t;
#define _R0 JIT_GPR(0)
#define _R1 JIT_GPR(1)
#define _R2 JIT_GPR(2)
#define _R3 JIT_GPR(3)
#define _R4 JIT_GPR(4)
#define _R5 JIT_GPR(5)
#define _R6 JIT_GPR(6)
#define _R7 JIT_GPR(7)
#define _R8 JIT_GPR(8)
#define _R9 JIT_GPR(9)
#define _R10 JIT_GPR(10)
#define _R11 JIT_GPR(11)
#define _R12 JIT_GPR(12)
#define _R13 JIT_GPR(13)
#define _R14 JIT_GPR(14)
#define _R15 JIT_GPR(15)
typedef struct {
uint32_t version : 4;
uint32_t extend : 1;
/* only generate thumb instructions for thumb2 */
uint32_t thumb : 1;
uint32_t vfp : 3;
uint32_t neon : 1;
uint32_t abi : 2;
/* use strt+offset instead of str.w?
* on special cases it causes a SIGILL at least on qemu, probably
* due to some memory ordering constraint not being respected, so,
* disable by default */
uint32_t ldrt_strt : 1;
} jit_cpu_t;
#define _D0 JIT_FPR(0)
#define _D1 JIT_FPR(2)
#define _D2 JIT_FPR(4)
#define _D3 JIT_FPR(6)
#define _D4 JIT_FPR(8)
#define _D5 JIT_FPR(10)
#define _D6 JIT_FPR(12)
#define _D7 JIT_FPR(14)
#define _D8 JIT_FPR(16)
#define _D9 JIT_FPR(18)
#define _D10 JIT_FPR(20)
#define _D11 JIT_FPR(22)
#define _D12 JIT_FPR(24)
#define _D13 JIT_FPR(26)
#define _D14 JIT_FPR(28)
#define _D15 JIT_FPR(30)
#define _S0 JIT_FPR(0)
#define _S1 JIT_FPR(1)
#define _S2 JIT_FPR(2)
#define _S3 JIT_FPR(3)
#define _S4 JIT_FPR(4)
#define _S5 JIT_FPR(5)
#define _S6 JIT_FPR(6)
#define _S7 JIT_FPR(7)
#define _S8 JIT_FPR(8)
#define _S9 JIT_FPR(9)
#define _S10 JIT_FPR(10)
#define _S11 JIT_FPR(11)
#define _S12 JIT_FPR(12)
#define _S13 JIT_FPR(13)
#define _S14 JIT_FPR(14)
#define _S15 JIT_FPR(15)
#define _S16 JIT_FPR(16)
#define _S17 JIT_FPR(17)
#define _S18 JIT_FPR(18)
#define _S19 JIT_FPR(19)
#define _S20 JIT_FPR(20)
#define _S21 JIT_FPR(21)
#define _S22 JIT_FPR(22)
#define _S23 JIT_FPR(23)
#define _S24 JIT_FPR(24)
#define _S25 JIT_FPR(25)
#define _S26 JIT_FPR(26)
#define _S27 JIT_FPR(27)
#define _S28 JIT_FPR(28)
#define _S29 JIT_FPR(29)
#define _S30 JIT_FPR(30)
#define _S31 JIT_FPR(31)
#define JIT_R0 _R0
#define JIT_R1 _R1
#define JIT_R2 _R2
#define JIT_R3 _R3
#define JIT_TMP0 _R12
#define JIT_V0 _R4
#define JIT_V1 _R5
#define JIT_V2 _R6
#define JIT_TMP1 _R7
#define JIT_V3 _R8
#define JIT_V4 _R9
#define JIT_V5 _R10
#define JIT_V6 _R11
#define JIT_SP _R13
#define _LR _R14
#define _PC _R15
#define JIT_F0 _D0
#define JIT_F1 _D1
#define JIT_F2 _D2
#define JIT_F3 _D3
#define JIT_F4 _D4
#define JIT_F5 _D5
#define JIT_F6 _D6
#define JIT_FTMP _D7
#define JIT_VF0 _D8
#define JIT_VF1 _D9
#define JIT_VF2 _D10
#define JIT_VF3 _D11
#define JIT_VF4 _D12
#define JIT_VF5 _D13
#define JIT_VF6 _D14
#define JIT_VF7 _D15
#define JIT_PLATFORM_CALLEE_SAVE_GPRS _LR, JIT_TMP1
/*
* Initialization
*/
JIT_API jit_cpu_t jit_cpu;
#endif /* _jit_arm_h */

View file

@ -29,14 +29,16 @@
#include "../lightening.h"
#define ASSERT(x) do { if (!(x)) abort(); } while (0)
#if defined(__GNUC__)
# define maybe_unused __attribute__ ((unused))
# define UNLIKELY(exprn) __builtin_expect(exprn, 0)
#else
# define maybe_unused /**/
# define UNLIKELY(exprn) exprn
#endif
#define _NOREG 0xffff
union jit_pc
{
uint8_t *uc;
@ -47,6 +49,23 @@ union jit_pc
uintptr_t uw;
};
#ifdef JIT_NEEDS_LITERAL_POOL
struct jit_literal_pool_entry
{
jit_reloc_t reloc;
int64_t value;
};
struct jit_literal_pool
{
uint32_t deadline;
uint32_t size;
uint32_t byte_size;
uint32_t capacity;
struct jit_literal_pool_entry entries[];
};
#endif // JIT_NEEDS_LITERAL_POOL
struct jit_state
{
union jit_pc pc;
@ -57,25 +76,50 @@ struct jit_state
uint8_t temp_fpr_saved;
uint8_t overflow;
int frame_size; // Used to know when to align stack.
#ifdef JIT_NEEDS_LITERAL_POOL
struct jit_literal_pool *pool;
#endif
void* (*alloc)(size_t);
void (*free)(void*);
};
#define ASSERT(x) do { if (!(x)) abort(); } while (0)
#if defined(__GNUC__)
# define UNLIKELY(exprn) __builtin_expect(exprn, 0)
#else
# define UNLIKELY(exprn) exprn
#endif
static jit_bool_t jit_get_cpu(void);
static jit_bool_t jit_init(jit_state_t *);
static void jit_flush(void *fptr, void *tptr);
static void jit_try_shorten(jit_state_t *_jit, jit_reloc_t reloc,
jit_pointer_t addr);
static void* bless_function_pointer(void *ptr);
struct abi_arg_iterator;
#ifdef JIT_NEEDS_LITERAL_POOL
static struct jit_literal_pool* alloc_literal_pool(jit_state_t *_jit,
size_t capacity);
static void clear_literal_pool(struct jit_literal_pool *pool);
static void grow_literal_pool(jit_state_t *_jit);
static void add_literal_pool_entry(jit_state_t *_jit,
struct jit_literal_pool_entry entry,
ptrdiff_t max_offset);
static void add_pending_literal(jit_state_t *_jit, jit_reloc_t src,
ptrdiff_t max_offset_bits);
static void remove_pending_literal(jit_state_t *_jit, jit_reloc_t src);
static void patch_pending_literal(jit_state_t *_jit, jit_reloc_t src,
uint64_t value);
enum guard_pool { GUARD_NEEDED, NO_GUARD_NEEDED };
static void emit_literal_pool(jit_state_t *_jit, enum guard_pool guard);
static int32_t read_jmp_offset(uint32_t *loc);
static int offset_in_jmp_range(ptrdiff_t offset);
static void patch_jmp_offset(uint32_t *loc, ptrdiff_t offset);
static int32_t read_jcc_offset(uint32_t *loc);
static int offset_in_jcc_range(ptrdiff_t offset);
static void patch_jcc_offset(uint32_t *loc, ptrdiff_t offset);
static void patch_veneer(uint32_t *loc, jit_pointer_t addr);
static int32_t read_load_from_pool_offset(uint32_t *loc);
#endif
static jit_bool_t is_fpr_arg(enum jit_operand_abi arg);
static jit_bool_t is_gpr_arg(enum jit_operand_abi arg);
static void reset_abi_arg_iterator(struct abi_arg_iterator *iter, size_t argc,
const jit_operand_t *args);
static void next_abi_arg(struct abi_arg_iterator *iter,
@ -102,16 +146,26 @@ jit_new_state(void* (*alloc_fn)(size_t), void (*free_fn)(void*))
_jit->free = free_fn;
if (!jit_init (_jit)) {
#ifdef JIT_NEEDS_LITERAL_POOL
free_fn (_jit->pool);
#endif
free_fn (_jit);
return NULL;
}
#ifdef JIT_NEEDS_LITERAL_POOL
_jit->pool = alloc_literal_pool(_jit, 0);
#endif
return _jit;
}
void
jit_destroy_state(jit_state_t *_jit)
{
#ifdef JIT_NEEDS_LITERAL_POOL
_jit->free (_jit->pool);
#endif
_jit->free (_jit);
}
@ -131,6 +185,9 @@ jit_begin(jit_state_t *_jit, uint8_t* buf, size_t length)
_jit->limit = buf + length;
_jit->overflow = 0;
_jit->frame_size = 0;
#ifdef JIT_NEEDS_LITERAL_POOL
clear_literal_pool(_jit->pool);
#endif
}
jit_bool_t
@ -147,30 +204,43 @@ jit_reset(jit_state_t *_jit)
_jit->pc.uc = _jit->start = _jit->limit = NULL;
_jit->overflow = 0;
_jit->frame_size = 0;
#ifdef JIT_NEEDS_LITERAL_POOL
clear_literal_pool(_jit->pool);
#endif
}
void*
jit_end(jit_state_t *_jit, size_t *length)
{
uint8_t *code = _jit->start;
#ifdef JIT_NEEDS_LITERAL_POOL
if (_jit->pool->size)
emit_literal_pool(_jit, NO_GUARD_NEEDED);
#endif
if (_jit->overflow)
return NULL;
uint8_t *start = _jit->start;
uint8_t *end = _jit->pc.uc;
ASSERT (code);
ASSERT (code <= end);
ASSERT (start);
ASSERT (start <= end);
ASSERT (end <= _jit->limit);
ASSERT (!_jit->overflow);
jit_flush (code, end);
jit_flush (start, end);
if (length) {
*length = end - code;
*length = end - start;
}
_jit->pc.uc = _jit->start = _jit->limit = NULL;
_jit->overflow = 0;
_jit->frame_size = 0;
#ifdef JIT_NEEDS_LITERAL_POOL
clear_literal_pool(_jit->pool);
#endif
return code;
return bless_function_pointer(start);
}
static int
@ -179,14 +249,46 @@ is_power_of_two (unsigned x)
return x && !(x & (x-1));
}
void
jit_align(jit_state_t *_jit, unsigned align)
static jit_gpr_t
get_temp_gpr(jit_state_t *_jit)
{
ASSERT (is_power_of_two (align));
uintptr_t here = _jit->pc.w;
uintptr_t there = (here + align - 1) & ~(align - 1);
if (there - here)
jit_nop(_jit, there - here);
switch(_jit->temp_gpr_saved++)
{
case 0:
return JIT_TMP0;
#ifdef JIT_TMP1
case 1:
return JIT_TMP1;
#endif
default:
abort();
}
}
static jit_fpr_t
get_temp_fpr(jit_state_t *_jit)
{
switch(_jit->temp_fpr_saved++)
{
case 0:
return JIT_FTMP;
default:
abort();
}
}
static void
unget_temp_fpr(jit_state_t *_jit)
{
ASSERT(_jit->temp_fpr_saved);
_jit->temp_fpr_saved--;
}
static void
unget_temp_gpr(jit_state_t *_jit)
{
ASSERT(_jit->temp_gpr_saved);
_jit->temp_gpr_saved--;
}
static inline void emit_u8(jit_state_t *_jit, uint8_t u8) {
@ -210,6 +312,10 @@ static inline void emit_u32(jit_state_t *_jit, uint32_t u32) {
_jit->overflow = 1;
} else {
*_jit->pc.ui++ = u32;
#ifdef JIT_NEEDS_LITERAL_POOL
if (UNLIKELY(_jit->pc.uc >= _jit->start + _jit->pool->deadline))
emit_literal_pool(_jit, GUARD_NEEDED);
#endif
}
}
@ -223,38 +329,21 @@ static inline void emit_u64(jit_state_t *_jit, uint64_t u64) {
static inline jit_reloc_t
jit_reloc (jit_state_t *_jit, enum jit_reloc_kind kind,
uint8_t inst_start_offset)
uint8_t inst_start_offset, uint8_t *loc, uint8_t *pc_base,
uint8_t rsh)
{
jit_reloc_t ret;
ASSERT(rsh < __WORDSIZE);
ASSERT(pc_base >= (loc - inst_start_offset));
ASSERT(pc_base - (loc - inst_start_offset) < 256);
ret.kind = kind;
ret.inst_start_offset = inst_start_offset;
ret.offset = _jit->pc.uc - _jit->start;
ret.pc_base_offset = pc_base - (loc - inst_start_offset);
ret.rsh = rsh;
ret.offset = loc - _jit->start;
switch (kind)
{
case JIT_RELOC_ABSOLUTE:
if (sizeof(intptr_t) == 4)
emit_u32 (_jit, 0);
else
emit_u64 (_jit, 0);
break;
case JIT_RELOC_REL8:
emit_u8 (_jit, 0);
break;
case JIT_RELOC_REL16:
emit_u16 (_jit, 0);
break;
case JIT_RELOC_REL32:
emit_u32 (_jit, 0);
break;
case JIT_RELOC_REL64:
emit_u64 (_jit, 0);
break;
default:
abort ();
}
return ret;
}
@ -272,7 +361,10 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
union jit_pc loc;
uint8_t *end;
loc.uc = _jit->start + reloc.offset;
ptrdiff_t diff;
uint8_t *pc_base = loc.uc - reloc.inst_start_offset + reloc.pc_base_offset;
ptrdiff_t diff = (uint8_t*)addr - pc_base;
ASSERT((diff & ((1 << reloc.rsh) - 1)) == 0);
diff >>= reloc.rsh;
switch (reloc.kind)
{
@ -284,25 +376,68 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
end = loc.uc + sizeof(diff);
break;
case JIT_RELOC_REL8:
diff = ((uint8_t*)addr) - (loc.uc + 1);
ASSERT (INT8_MIN <= diff && diff <= INT8_MAX);
*loc.uc = diff;
end = loc.uc + 1;
break;
case JIT_RELOC_REL16:
diff = ((uint8_t*)addr) - (loc.uc + 2);
ASSERT (INT16_MIN <= diff && diff <= INT16_MAX);
*loc.us = diff;
end = loc.uc + 2;
break;
#ifdef JIT_NEEDS_LITERAL_POOL
case JIT_RELOC_JMP_WITH_VENEER: {
int32_t voff = read_jmp_offset(loc.ui);
uint8_t *target = pc_base + (voff << reloc.rsh);
if (target == loc.uc) {
// PC still in range to reify direct branch.
if (offset_in_jmp_range(diff)) {
// Target also in range: reify direct branch.
patch_jmp_offset(loc.ui, diff);
remove_pending_literal(_jit, reloc);
} else {
// Target out of range; branch to veneer.
patch_pending_literal(_jit, reloc, (uintptr_t) addr);
}
} else {
// Already emitted a veneer. In this case, patch the veneer
// directly.
patch_veneer((uint32_t *) target, addr);
}
return;
}
case JIT_RELOC_JCC_WITH_VENEER: {
int32_t voff = read_jcc_offset(loc.ui);
uint8_t *target = pc_base + (voff << reloc.rsh);
if (target == loc.uc) {
if (offset_in_jcc_range(diff)) {
patch_jcc_offset(loc.ui, diff);
remove_pending_literal(_jit, reloc);
} else {
patch_pending_literal(_jit, reloc, (uintptr_t) addr);
}
} else {
patch_veneer((uint32_t *) target, addr);
}
return;
}
case JIT_RELOC_LOAD_FROM_POOL: {
int32_t voff = read_load_from_pool_offset(loc.ui);
uint8_t *target = pc_base + (voff << reloc.rsh);
if (target == loc.uc) {
patch_pending_literal(_jit, reloc, (uintptr_t) addr);
} else {
*(uintptr_t *) target = (uintptr_t) addr;
}
return;
}
#endif
case JIT_RELOC_REL32:
diff = ((uint8_t*)addr) - (loc.uc + 4);
ASSERT (INT32_MIN <= diff && diff <= INT32_MAX);
*loc.ui = diff;
end = loc.uc + 4;
break;
case JIT_RELOC_REL64:
diff = ((uint8_t*)addr) - (loc.uc + 8);
*loc.ul = diff;
end = loc.uc + 8;
break;
@ -403,6 +538,45 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
FOR_EACH_INSTRUCTION(IMPL_INSTRUCTION)
#undef IMPL_INSTRUCTION
void
jit_align(jit_state_t *_jit, unsigned align)
{
ASSERT (is_power_of_two (align));
uintptr_t here = _jit->pc.w;
uintptr_t there = (here + align - 1) & ~(align - 1);
if (there - here)
nop(_jit, there - here);
}
static jit_bool_t
is_fpr_arg(enum jit_operand_abi arg)
{
switch (arg)
{
case JIT_OPERAND_ABI_UINT8:
case JIT_OPERAND_ABI_INT8:
case JIT_OPERAND_ABI_UINT16:
case JIT_OPERAND_ABI_INT16:
case JIT_OPERAND_ABI_UINT32:
case JIT_OPERAND_ABI_INT32:
case JIT_OPERAND_ABI_UINT64:
case JIT_OPERAND_ABI_INT64:
case JIT_OPERAND_ABI_POINTER:
return 0;
case JIT_OPERAND_ABI_FLOAT:
case JIT_OPERAND_ABI_DOUBLE:
return 1;
default:
abort();
}
}
static jit_bool_t
is_gpr_arg(enum jit_operand_abi arg)
{
return !is_fpr_arg(arg);
}
static void
abi_imm_to_gpr(jit_state_t *_jit, enum jit_operand_abi abi, jit_gpr_t dst,
intptr_t imm)
@ -570,10 +744,10 @@ abi_mem_to_mem(jit_state_t *_jit, enum jit_operand_abi abi, jit_gpr_t base,
abi_gpr_to_mem(_jit, abi, base, offset, tmp);
unget_temp_gpr(_jit);
} else {
jit_fpr_t tmp = get_temp_xpr(_jit);
jit_fpr_t tmp = get_temp_fpr(_jit);
abi_mem_to_fpr(_jit, abi, tmp, src_base, src_offset);
abi_fpr_to_mem(_jit, abi, base, offset, tmp);
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
}
@ -609,7 +783,11 @@ move_operand(jit_state_t *_jit, jit_operand_t dst, jit_operand_t src)
src.loc.mem.offset);
case MOVE_FPR_TO_FPR:
return jit_movr_d(_jit, dst.loc.fpr, src.loc.fpr);
ASSERT(src.abi == dst.abi);
if (src.abi == JIT_OPERAND_ABI_DOUBLE)
return jit_movr_d(_jit, dst.loc.fpr, src.loc.fpr);
else
return jit_movr_f(_jit, dst.loc.fpr, src.loc.fpr);
case MOVE_MEM_TO_FPR:
return abi_mem_to_fpr(_jit, src.abi, dst.loc.fpr, src.loc.mem.base,
@ -704,7 +882,7 @@ move_one(jit_state_t *_jit, jit_operand_t *dst, jit_operand_t *src,
jit_operand_t tmp;
if (is_fpr_arg (src[j].kind)) {
tmp_fpr = 1;
tmp = jit_operand_fpr(src[j].abi, get_temp_xpr(_jit));
tmp = jit_operand_fpr(src[j].abi, get_temp_fpr(_jit));
} else {
tmp_gpr = 1;
/* Preserve addend, if any, from source operand, to be applied
@ -729,7 +907,7 @@ move_one(jit_state_t *_jit, jit_operand_t *dst, jit_operand_t *src,
if (tmp_gpr)
unget_temp_gpr(_jit);
else if (tmp_fpr)
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
static void
@ -849,10 +1027,11 @@ jit_shrink_stack(jit_state_t *_jit, size_t diff)
_jit->frame_size -= diff;
}
static const jit_gpr_t V[] = {
#ifdef JIT_VTMP
JIT_VTMP ,
#endif
static const jit_gpr_t platform_callee_save_gprs[] = {
JIT_PLATFORM_CALLEE_SAVE_GPRS
};
static const jit_gpr_t user_callee_save_gprs[] = {
JIT_V0, JIT_V1, JIT_V2
#ifdef JIT_V3
, JIT_V3
@ -868,13 +1047,16 @@ static const jit_gpr_t V[] = {
#endif
#ifdef JIT_V7
, JIT_V7
#endif
#ifdef JIT_V8
, JIT_V8
#endif
#ifdef JIT_V9
, JIT_V9
#endif
};
static const jit_fpr_t VF[] = {
#ifdef JIT_VFTMP
JIT_VFTMP ,
#endif
static const jit_fpr_t user_callee_save_fprs[] = {
#ifdef JIT_VF0
JIT_VF0
#endif
@ -901,55 +1083,54 @@ static const jit_fpr_t VF[] = {
#endif
};
static const size_t v_count = sizeof(V) / sizeof(V[0]);
static const size_t vf_count = sizeof(VF) / sizeof(VF[0]);
#define ARRAY_SIZE(X) (sizeof (X)/sizeof ((X)[0]))
static const size_t pv_count = ARRAY_SIZE(platform_callee_save_gprs);
static const size_t v_count = ARRAY_SIZE(user_callee_save_gprs);
static const size_t vf_count = ARRAY_SIZE(user_callee_save_fprs);
size_t
jit_enter_jit_abi(jit_state_t *_jit, size_t v, size_t vf, size_t frame_size)
{
#ifdef JIT_VTMP
v++;
#endif
#ifdef JIT_VFTMP
vf++;
#endif
ASSERT(v <= v_count);
ASSERT(vf <= vf_count);
ASSERT(_jit->frame_size == 0);
_jit->frame_size = jit_initial_frame_size();
/* Save values of callee-save registers. */
for (size_t i = 0; i < v; i++)
jit_pushr (_jit, V[i]);
for (size_t i = 0; i < vf; i++)
jit_pushr_d (_jit, VF[i]);
size_t reserved =
jit_align_stack(_jit, (pv_count + v) * (__WORDSIZE / 8) + vf * 8);
return jit_align_stack(_jit, frame_size);
size_t offset = 0;
for (size_t i = 0; i < vf; i++, offset += 8)
jit_stxi_d(_jit, offset, JIT_SP, user_callee_save_fprs[i]);
for (size_t i = 0; i < v; i++, offset += __WORDSIZE / 8)
jit_stxi(_jit, offset, JIT_SP, user_callee_save_gprs[i]);
for (size_t i = 0; i < pv_count; i++, offset += __WORDSIZE / 8)
jit_stxi(_jit, offset, JIT_SP, platform_callee_save_gprs[i]);
ASSERT(offset <= reserved);
return reserved;
}
void
jit_leave_jit_abi(jit_state_t *_jit, size_t v, size_t vf, size_t frame_size)
{
#ifdef JIT_VTMP
v++;
#endif
#ifdef JIT_VFTMP
vf++;
#endif
ASSERT(v <= v_count);
ASSERT(vf <= vf_count);
ASSERT((pv_count + v) * (__WORDSIZE / 8) + vf * 8 <= frame_size);
size_t offset = 0;
for (size_t i = 0; i < vf; i++, offset += 8)
jit_ldxi_d(_jit, user_callee_save_fprs[i], JIT_SP, offset);
for (size_t i = 0; i < v; i++, offset += __WORDSIZE / 8)
jit_ldxi(_jit, user_callee_save_gprs[i], JIT_SP, offset);
for (size_t i = 0; i < pv_count; i++, offset += __WORDSIZE / 8)
jit_ldxi(_jit, platform_callee_save_gprs[i], JIT_SP, offset);
ASSERT(offset <= frame_size);
jit_shrink_stack(_jit, frame_size);
/* Restore callee-save registers. */
for (size_t i = 0; i < vf; i++)
jit_popr_d (_jit, VF[vf - i - 1]);
for (size_t i = 0; i < v; i++)
jit_popr (_jit, V[v - i - 1]);
}
// Precondition: stack is already aligned.
static size_t
prepare_call_args(jit_state_t *_jit, size_t argc, jit_operand_t args[])
@ -969,7 +1150,7 @@ prepare_call_args(jit_state_t *_jit, size_t argc, jit_operand_t args[])
for (size_t i = 0; i < argc; i++) {
switch(args[i].kind) {
case JIT_OPERAND_KIND_GPR:
if (jit_same_gprs (args[i].loc.mem.base, JIT_SP))
if (jit_same_gprs (args[i].loc.gpr.gpr, JIT_SP))
args[i].loc.gpr.addend += stack_size;
break;
case JIT_OPERAND_KIND_MEM:
@ -1029,3 +1210,147 @@ jit_load_args(jit_state_t *_jit, size_t argc, jit_operand_t args[])
jit_locate_args(_jit, argc, src);
jit_move_operands(_jit, args, src, argc);
}
#ifdef JIT_NEEDS_LITERAL_POOL
#define INITIAL_LITERAL_POOL_CAPACITY 12
static struct jit_literal_pool*
alloc_literal_pool(jit_state_t *_jit, size_t capacity)
{
if (capacity == 0) capacity = INITIAL_LITERAL_POOL_CAPACITY;
struct jit_literal_pool *ret =
_jit->alloc (sizeof (struct jit_literal_pool) +
sizeof (struct jit_literal_pool_entry) * capacity);
ASSERT (ret);
ret->deadline = -1;
ret->size = 0;
ret->capacity = capacity;
return ret;
}
static void
clear_literal_pool(struct jit_literal_pool *pool)
{
pool->deadline = -1;
pool->size = 0;
}
static void
grow_literal_pool(jit_state_t *_jit)
{
struct jit_literal_pool *new_pool =
alloc_literal_pool(_jit, _jit->pool->capacity * 2);
for (size_t i = 0; i < _jit->pool->size; i++)
new_pool->entries[new_pool->size++] = _jit->pool->entries[i];
new_pool->deadline = _jit->pool->deadline;
_jit->free (_jit->pool);
_jit->pool = new_pool;
}
static void
add_literal_pool_entry(jit_state_t *_jit, struct jit_literal_pool_entry entry,
ptrdiff_t max_offset)
{
if (_jit->pool->size == _jit->pool->capacity)
grow_literal_pool (_jit);
max_offset <<= entry.reloc.rsh;
ptrdiff_t deadline =
_jit->pc.uc - _jit->start + max_offset - _jit->pool->byte_size;
if (_jit->pool->size == 0)
// Assume that we might need a uint32_t for alignment, and another
// to branch over the table.
_jit->pool->deadline = deadline - 2 * sizeof(uint32_t);
else if (deadline < _jit->pool->deadline)
_jit->pool->deadline = deadline;
// Assume that each entry takes a max of 16 bytes.
_jit->pool->byte_size += 16;
_jit->pool->entries[_jit->pool->size++] = entry;
}
static void
add_pending_literal(jit_state_t *_jit, jit_reloc_t src,
ptrdiff_t max_offset_bits)
{
struct jit_literal_pool_entry entry = { src, 0 };
add_literal_pool_entry(_jit, entry,
(1 << (max_offset_bits + src.rsh)) - 1);
}
static void
remove_pending_literal(jit_state_t *_jit, jit_reloc_t src)
{
for (size_t i = _jit->pool->size; i--; ) {
if (_jit->pool->entries[i].reloc.offset == src.offset) {
for (size_t j = i + 1; j < _jit->pool->size; j++)
_jit->pool->entries[j-1] = _jit->pool->entries[j];
_jit->pool->size--;
return;
}
}
abort();
}
static void
patch_pending_literal(jit_state_t *_jit, jit_reloc_t src, uint64_t value)
{
for (size_t i = _jit->pool->size; i--; ) {
if (_jit->pool->entries[i].reloc.offset == src.offset) {
ASSERT(_jit->pool->entries[i].value == 0);
_jit->pool->entries[i].value = value;
return;
}
}
abort();
}
static void
emit_literal_pool(jit_state_t *_jit, enum guard_pool guard)
{
_jit->pool->deadline = -1;
if (!_jit->pool->size)
return;
jit_reloc_t skip;
if (guard == GUARD_NEEDED)
skip = jit_jmp(_jit);
// FIXME: Could de-duplicate constants.
for (size_t i = 0; i < _jit->pool->size; i++) {
jit_align(_jit, 8);
struct jit_literal_pool_entry *entry = &_jit->pool->entries[i];
uint8_t *loc = _jit->start + entry->reloc.offset;
uint8_t *pc_base =
loc - entry->reloc.inst_start_offset + entry->reloc.pc_base_offset;
ptrdiff_t diff = _jit->pc.uc - pc_base;
diff >>= entry->reloc.rsh;
switch (entry->reloc.kind) {
case JIT_RELOC_JMP_WITH_VENEER:
patch_jmp_offset((uint32_t*) loc, diff);
emit_veneer(_jit, (void*) (uintptr_t) entry->value);
break;
case JIT_RELOC_JCC_WITH_VENEER:
patch_jcc_offset((uint32_t*) loc, diff);
emit_veneer(_jit, (void*) (uintptr_t) entry->value);
break;
case JIT_RELOC_LOAD_FROM_POOL:
patch_load_from_pool_offset((uint32_t*) loc, diff);
emit_u64(_jit, entry->value);
break;
default:
abort();
}
}
if (guard == GUARD_NEEDED)
jit_patch_here(_jit, skip);
clear_literal_pool(_jit->pool);
}
#endif

View file

@ -265,25 +265,6 @@ popr(jit_state_t *_jit, int32_t r0)
ic(_jit, 0x58 | r7(r0));
}
static jit_gpr_t
get_temp_gpr(jit_state_t *_jit)
{
ASSERT(!_jit->temp_gpr_saved);
_jit->temp_gpr_saved = 1;
#ifdef JIT_RTMP
return JIT_RTMP;
#else
return JIT_VTMP;
#endif
}
static void
unget_temp_gpr(jit_state_t *_jit)
{
ASSERT(_jit->temp_gpr_saved);
_jit->temp_gpr_saved = 0;
}
static void
nop(jit_state_t *_jit, int32_t count)
{
@ -397,7 +378,7 @@ mov_addr(jit_state_t *_jit, int32_t r0)
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
ic(_jit, 0xb8 | r7(r0));
ptrdiff_t inst_start = _jit->pc.uc - pc_start;
return jit_reloc(_jit, JIT_RELOC_ABSOLUTE, inst_start);
return emit_abs_reloc(_jit, inst_start);
}
static void
@ -2128,7 +2109,7 @@ static jit_reloc_t
jccs(jit_state_t *_jit, int32_t code)
{
ic(_jit, 0x70 | code);
return jit_reloc(_jit, JIT_RELOC_REL8, 1);
return emit_rel8_reloc(_jit, 1);
}
static jit_reloc_t
@ -2136,7 +2117,7 @@ jcc(jit_state_t *_jit, int32_t code)
{
ic(_jit, 0x0f);
ic(_jit, 0x80 | code);
return jit_reloc(_jit, JIT_RELOC_REL32, 2);
return emit_rel32_reloc(_jit, 2);
}
static void
@ -2583,7 +2564,7 @@ static jit_reloc_t
jmp(jit_state_t *_jit)
{
ic(_jit, 0xe9);
return jit_reloc(_jit, JIT_RELOC_REL32, 1);
return emit_rel32_reloc(_jit, 1);
}
static void

View file

@ -169,39 +169,6 @@ movr_d(jit_state_t *_jit, int32_t r0, int32_t r1)
ssexr(_jit, 0xf2, X86_SSE_MOV, r0, r1);
}
static void
pushr_d(jit_state_t *_jit, int32_t r0)
{
jit_gpr_t tmp = get_temp_gpr(_jit);
movdqxr(_jit, jit_gpr_regno(tmp), r0);
pushr(_jit, jit_gpr_regno(tmp));
unget_temp_gpr(_jit);
}
static void
popr_d(jit_state_t *_jit, int32_t r0)
{
jit_gpr_t tmp = get_temp_gpr(_jit);
popr(_jit, jit_gpr_regno(tmp));
ssexr(_jit, 0x66, X86_SSE_G2X, r0, jit_gpr_regno(tmp));
unget_temp_gpr(_jit);
}
static jit_fpr_t
get_temp_xpr(jit_state_t *_jit)
{
ASSERT(!_jit->temp_fpr_saved);
_jit->temp_fpr_saved = 1;
return JIT_FTMP;
}
static void
unget_temp_xpr(jit_state_t *_jit)
{
ASSERT(_jit->temp_fpr_saved);
_jit->temp_fpr_saved = 0;
}
static void
addssr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
@ -409,14 +376,14 @@ movi_d(jit_state_t *_jit, int32_t r0, jit_float64_t i0)
movdqxr(_jit, r0, jit_gpr_regno(ireg));
unget_temp_gpr(_jit);
#else
jit_fpr_t freg = get_temp_xpr(_jit);
jit_fpr_t freg = get_temp_fpr(_jit);
movi(_jit, jit_gpr_regno(ireg), data.ii[1]);
movdlxr(_jit, jit_fpr_regno(freg), jit_gpr_regno(ireg));
pslq(_jit, jit_fpr_regno(freg), 32);
movi(_jit, jit_gpr_regno(ireg), data.ii[0]);
movdlxr(_jit, r0, jit_gpr_regno(ireg));
orpdr(_jit, r0, jit_fpr_regno(freg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
unget_temp_gpr(_jit);
#endif
}
@ -543,11 +510,11 @@ subr_f(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
if (r0 == r1)
subssr(_jit, r0, r2);
else if (r0 == r2) {
jit_fpr_t reg = get_temp_xpr(_jit);
jit_fpr_t reg = get_temp_fpr(_jit);
movr_f(_jit, jit_fpr_regno(reg), r0);
movr_f(_jit, r0, r1);
subssr(_jit, r0, jit_fpr_regno(reg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
else {
movr_f(_jit, r0, r1);
@ -561,11 +528,11 @@ subr_d(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
if (r0 == r1)
subsdr(_jit, r0, r2);
else if (r0 == r2) {
jit_fpr_t reg = get_temp_xpr(_jit);
jit_fpr_t reg = get_temp_fpr(_jit);
movr_d(_jit, jit_fpr_regno(reg), r0);
movr_d(_jit, r0, r1);
subsdr(_jit, r0, jit_fpr_regno(reg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
else {
movr_d(_jit, r0, r1);
@ -605,11 +572,11 @@ divr_f(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
if (r0 == r1)
divssr(_jit, r0, r2);
else if (r0 == r2) {
jit_fpr_t reg = get_temp_xpr(_jit);
jit_fpr_t reg = get_temp_fpr(_jit);
movr_f(_jit, jit_fpr_regno(reg), r0);
movr_f(_jit, r0, r1);
divssr(_jit, r0, jit_fpr_regno(reg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
else {
movr_f(_jit, r0, r1);
@ -623,11 +590,11 @@ divr_d(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
if (r0 == r1)
divsdr(_jit, r0, r2);
else if (r0 == r2) {
jit_fpr_t reg = get_temp_xpr(_jit);
jit_fpr_t reg = get_temp_fpr(_jit);
movr_d(_jit, jit_fpr_regno(reg), r0);
movr_d(_jit, r0, r1);
divsdr(_jit, r0, jit_fpr_regno(reg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
else {
movr_d(_jit, r0, r1);
@ -639,11 +606,11 @@ static void
absr_f(jit_state_t *_jit, int32_t r0, int32_t r1)
{
if (r0 == r1) {
jit_fpr_t reg = get_temp_xpr(_jit);
jit_fpr_t reg = get_temp_fpr(_jit);
pcmpeqlr(_jit, jit_fpr_regno(reg), jit_fpr_regno(reg));
psrl(_jit, jit_fpr_regno(reg), 1);
andpsr(_jit, r0, jit_fpr_regno(reg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
else {
pcmpeqlr(_jit, r0, r0);
@ -656,11 +623,11 @@ static void
absr_d(jit_state_t *_jit, int32_t r0, int32_t r1)
{
if (r0 == r1) {
jit_fpr_t reg = get_temp_xpr(_jit);
jit_fpr_t reg = get_temp_fpr(_jit);
pcmpeqlr(_jit, jit_fpr_regno(reg), jit_fpr_regno(reg));
psrq(_jit, jit_fpr_regno(reg), 1);
andpdr(_jit, r0, jit_fpr_regno(reg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
}
else {
pcmpeqlr(_jit, r0, r0);
@ -675,10 +642,10 @@ negr_f(jit_state_t *_jit, int32_t r0, int32_t r1)
jit_gpr_t ireg = get_temp_gpr(_jit);
imovi(_jit, jit_gpr_regno(ireg), 0x80000000);
if (r0 == r1) {
jit_fpr_t freg = get_temp_xpr(_jit);
jit_fpr_t freg = get_temp_fpr(_jit);
movdlxr(_jit, jit_fpr_regno(freg), jit_gpr_regno(ireg));
xorpsr(_jit, r0, jit_fpr_regno(freg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
} else {
movdlxr(_jit, r0, jit_gpr_regno(ireg));
xorpsr(_jit, r0, r1);
@ -692,11 +659,11 @@ negr_d(jit_state_t *_jit, int32_t r0, int32_t r1)
jit_gpr_t ireg = get_temp_gpr(_jit);
imovi(_jit, jit_gpr_regno(ireg), 0x80000000);
if (r0 == r1) {
jit_fpr_t freg = get_temp_xpr(_jit);
jit_fpr_t freg = get_temp_fpr(_jit);
movdlxr(_jit, jit_fpr_regno(freg), jit_gpr_regno(ireg));
pslq(_jit, jit_fpr_regno(freg), 32);
xorpdr(_jit, r0, jit_fpr_regno(freg));
unget_temp_xpr(_jit);
unget_temp_fpr(_jit);
} else {
movdlxr(_jit, r0, jit_gpr_regno(ireg));
pslq(_jit, r0, 32);

View file

@ -17,6 +17,8 @@
* Paulo Cesar Pereira de Andrade
*/
#define _NOREG 0xffff
typedef struct {
/* x87 present */
uint32_t fpu : 1;
@ -58,6 +60,33 @@ typedef struct {
static jit_cpu_t jit_cpu;
static inline jit_reloc_t
emit_rel8_reloc (jit_state_t *_jit, uint8_t inst_start)
{
uint8_t *loc = _jit->pc.uc;
emit_u8 (_jit, 0);
return jit_reloc(_jit, JIT_RELOC_REL8, inst_start, loc, _jit->pc.uc, 0);
}
static inline jit_reloc_t
emit_rel32_reloc (jit_state_t *_jit, uint8_t inst_start)
{
uint8_t *loc = _jit->pc.uc;
emit_u32 (_jit, 0);
return jit_reloc(_jit, JIT_RELOC_REL32, inst_start, loc, _jit->pc.uc, 0);
}
static inline jit_reloc_t
emit_abs_reloc (jit_state_t *_jit, uint8_t inst_start)
{
uint8_t *loc = _jit->pc.uc;
if (sizeof(intptr_t) == 4)
emit_u32 (_jit, 0);
else
emit_u64 (_jit, 0);
return jit_reloc(_jit, JIT_RELOC_ABSOLUTE, inst_start, loc, _jit->pc.uc, 0);
}
#include "x86-cpu.c"
#include "x86-sse.c"
@ -216,35 +245,6 @@ jit_init(jit_state_t *_jit)
return jit_cpu.sse2;
}
static jit_bool_t
is_fpr_arg(enum jit_operand_abi arg)
{
switch (arg)
{
case JIT_OPERAND_ABI_UINT8:
case JIT_OPERAND_ABI_INT8:
case JIT_OPERAND_ABI_UINT16:
case JIT_OPERAND_ABI_INT16:
case JIT_OPERAND_ABI_UINT32:
case JIT_OPERAND_ABI_INT32:
case JIT_OPERAND_ABI_UINT64:
case JIT_OPERAND_ABI_INT64:
case JIT_OPERAND_ABI_POINTER:
return 0;
case JIT_OPERAND_ABI_FLOAT:
case JIT_OPERAND_ABI_DOUBLE:
return 1;
default:
abort();
}
}
static jit_bool_t
is_gpr_arg(enum jit_operand_abi arg)
{
return !is_fpr_arg(arg);
}
static const jit_gpr_t abi_gpr_args[] = {
#if __X32
/* No GPRs in args. */
@ -353,7 +353,7 @@ next_abi_arg(struct abi_arg_iterator *iter, jit_operand_t *arg)
iter->arg_idx++;
}
void
static void
jit_flush(void *fptr, void *tptr)
{
}
@ -387,9 +387,6 @@ jit_try_shorten(jit_state_t *_jit, jit_reloc_t reloc, jit_pointer_t addr)
ASSERT((loc[-1] & ~0xf) == 0x70 || loc[-1] == 0xeb); // JCCSI or JMPSI
/* Nothing useful to do. */
return;
case JIT_RELOC_REL16:
/* We don't emit these. */
abort ();
case JIT_RELOC_REL32:
_jit->pc.uc = start;
if (start[0] == 0xe9) { // JMP
@ -397,10 +394,14 @@ jit_try_shorten(jit_state_t *_jit, jit_reloc_t reloc, jit_pointer_t addr)
}
ASSERT(start[0] == 0x0f); // JCC
return jcci(_jit, start[1] & ~0x80, i0);
case JIT_RELOC_REL64:
/* We don't emit these. */
abort ();
default:
/* We don't emit other kinds of reloc. */
abort ();
}
}
static void*
bless_function_pointer(void *ptr)
{
return ptr;
}

View file

@ -20,9 +20,6 @@
#ifndef _jit_x86_h
#define _jit_x86_h
/*
* Types
*/
#if __WORDSIZE == 32
# if defined(__x86_64__)
# define __X64 1
@ -76,54 +73,6 @@
# define _XMM15 JIT_FPR(15)
#endif
static inline jit_bool_t
jit_gpr_is_callee_save (jit_gpr_t reg)
{
#if __X32
return jit_same_gprs (reg, _RBX) ||
jit_same_gprs (reg, _RBP) ||
jit_same_gprs (reg, _RSI) ||
jit_same_gprs (reg, _RDI);
#elif __CYGWIN__
return jit_same_gprs (reg, _RBX) ||
jit_same_gprs (reg, _RBP) ||
jit_same_gprs (reg, _RSI) ||
jit_same_gprs (reg, _RDI) ||
jit_same_gprs (reg, _R12) ||
jit_same_gprs (reg, _R13) ||
jit_same_gprs (reg, _R14) ||
jit_same_gprs (reg, _R15);
#else
return jit_same_gprs (reg, _RBX) ||
jit_same_gprs (reg, _RBP) ||
jit_same_gprs (reg, _R12) ||
jit_same_gprs (reg, _R13) ||
jit_same_gprs (reg, _R14) ||
jit_same_gprs (reg, _R15);
#endif
}
static inline jit_bool_t
jit_fpr_is_callee_save (jit_fpr_t reg)
{
#if __X32
return 0;
#elif __CYGWIN__
return jit_same_fprs (reg, _XMM6) ||
jit_same_fprs (reg, _XMM7) ||
jit_same_fprs (reg, _XMM8) ||
jit_same_fprs (reg, _XMM9) ||
jit_same_fprs (reg, _XMM10) ||
jit_same_fprs (reg, _XMM11) ||
jit_same_fprs (reg, _XMM12) ||
jit_same_fprs (reg, _XMM13) ||
jit_same_fprs (reg, _XMM14) ||
jit_same_fprs (reg, _XMM15);
#else
return 0;
#endif
}
#define JIT_SP _RSP
#if __X32
# define JIT_R0 _RAX
@ -132,7 +81,7 @@ jit_fpr_is_callee_save (jit_fpr_t reg)
# define JIT_V0 _RBP
# define JIT_V1 _RSI
# define JIT_V2 _RDI
# define JIT_VTMP _RBX
# define JIT_TMP0 _RBX
# define JIT_F0 _XMM0
# define JIT_F1 _XMM1
# define JIT_F2 _XMM2
@ -141,6 +90,7 @@ jit_fpr_is_callee_save (jit_fpr_t reg)
# define JIT_F5 _XMM5
# define JIT_F6 _XMM6
# define JIT_FTMP _XMM7
# define JIT_PLATFORM_CALLEE_SAVE_GPRS JIT_TMP0
#elif __CYGWIN__
# define JIT_R0 _RAX
# define JIT_R1 _RCX
@ -148,7 +98,7 @@ jit_fpr_is_callee_save (jit_fpr_t reg)
# define JIT_R3 _R8
# define JIT_R4 _R9
# define JIT_R5 _R10
# define JIT_RTMP _R11
# define JIT_TMP0 _R11
# define JIT_V0 _RBX
# define JIT_V1 _RSI
# define JIT_V2 _RDI
@ -172,6 +122,7 @@ jit_fpr_is_callee_save (jit_fpr_t reg)
# define JIT_VF7 _XMM13
# define JIT_VF8 _XMM14
# define JIT_VF9 _XMM15
# define JIT_PLATFORM_CALLEE_SAVE_GPRS /**/
#else
# define JIT_R0 _RAX
# define JIT_R1 _RCX
@ -181,7 +132,7 @@ jit_fpr_is_callee_save (jit_fpr_t reg)
# define JIT_R5 _R8
# define JIT_R6 _R9
# define JIT_R7 _R10
# define JIT_RTMP _R11
# define JIT_TMP0 _R11
# define JIT_V0 _RBX
# define JIT_V1 _R12
# define JIT_V2 _R13
@ -203,6 +154,7 @@ jit_fpr_is_callee_save (jit_fpr_t reg)
# define JIT_F13 _XMM13
# define JIT_F14 _XMM14
# define JIT_FTMP _XMM15
# define JIT_PLATFORM_CALLEE_SAVE_GPRS /**/
#endif
#endif /* _jit_x86_h */

View file

@ -1,8 +1,26 @@
TESTS=$(sort $(basename $(wildcard *.c)))
TARGETS=native
TARGETS=native ia32 aarch64
ALL_TARGETS=$(TARGETS) armv7
# Suitable values of cross-compiler variables for Debian:
#
# make test CC_IA32=i668-linux-gnu-gcc CC_AARCH64=aarch64-linux-gnu-gcc
#
# The relevant packages that you need to run this:
#
# dpkg --add-architecture i386
# dpkg --add-architecture arm64
# apt-get update -qq
# apt-get install -y \
# libc6-dev:amd64 gcc make \
# qemu binfmt-support qemu-user-static \
# gcc-i686-linux-gnu libc6-dev-i386-cross libc6:i386 \
# gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6:arm64
#
CC = gcc
CC_IA32 = gcc -m32
CC_IA32=guix environment --pure -s i686-linux --ad-hoc gcc-toolchain glibc -- gcc
CC_AARCH64=guix environment --pure -s aarch64-linux --ad-hoc gcc-toolchain glibc -- gcc
CC_ARMv7=guix environment --pure -s armhf-linux --ad-hoc gcc-toolchain glibc -- gcc
CFLAGS = -Wall -O0 -g
all: $(foreach TARGET,$(TARGETS),$(addprefix test-$(TARGET)-,$(TESTS)))
@ -29,9 +47,17 @@ test-ia32-%: CC = $(CC_IA32)
test-ia32-%: %.c lightening-ia32.o test.h
$(CC) $(CFLAGS) $(CPPFLAGS) -I.. -o $@ lightening-ia32.o $<
.PRECIOUS: $(foreach TARGET,$(TARGETS),$(addprefix test-$(TARGET)-,$(TESTS)))
.PRECIOUS: $(foreach TARGET,$(TARGETS),lightening-$(TARGET).o)
test-aarch64-%: CC = $(CC_AARCH64)
test-aarch64-%: %.c lightening-aarch64.o test.h
$(CC) $(CFLAGS) $(CPPFLAGS) -I.. -o $@ lightening-aarch64.o $<
test-armv7-%: CC = $(CC_ARMv7)
test-armv7-%: %.c lightening-armv7.o test.h
$(CC) $(CFLAGS) $(CPPFLAGS) -I.. -o $@ lightening-armv7.o $<
.PRECIOUS: $(foreach TARGET,$(ALL_TARGETS),$(addprefix test-$(TARGET)-,$(TESTS)))
.PRECIOUS: $(foreach TARGET,$(ALL_TARGETS),lightening-$(TARGET).o)
clean:
rm -f $(foreach TARGET,$(TARGETS),$(addprefix test-$(TARGET)-,$(TESTS)))
rm -f $(foreach TARGET,$(TARGETS),lightening-$(TARGET).o)
rm -f $(foreach TARGET,$(ALL_TARGETS),$(addprefix test-$(TARGET)-,$(TESTS)))
rm -f $(foreach TARGET,$(ALL_TARGETS),lightening-$(TARGET).o)

View file

@ -1,26 +0,0 @@
#include "test.h"
static void
run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size)
{
jit_begin(j, arena_base, arena_size);
size_t align = jit_enter_jit_abi(j, 0, 0, 0);
size_t total = 0;
char *start = jit_address(j);
for (size_t i = 1; i < 10; total += i, i++)
jit_nop(j, i);
char *end = jit_address(j);
ASSERT(end - start == total);
jit_leave_jit_abi(j, 0, 0, align);
jit_reti(j, 42);
jit_word_t (*f)(void) = jit_end(j, NULL);
ASSERT(f() == 42);
}
int
main (int argc, char *argv[])
{
return main_helper(argc, argv, run_test);
}

View file

@ -1,35 +0,0 @@
#include "test.h"
static void
run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size)
{
const jit_gpr_t gpr[] = { JIT_R0, JIT_R1, JIT_R2, JIT_V0, JIT_V1, JIT_V2 };
const jit_fpr_t fpr[] = { JIT_F0, JIT_F1, JIT_F2 };
jit_begin(j, arena_base, arena_size);
size_t align = jit_enter_jit_abi(j, 3, 0, 0);
jit_load_args_1(j, jit_operand_gpr (JIT_OPERAND_ABI_WORD, JIT_R0));
jit_pushr(j, JIT_R0);
// Stomple registers.
for (int i=0; i<6; i++)
jit_movi(j, gpr[i], 0xcabba9e5);
for (int i=0; i<3; i++)
jit_extr_d(j, fpr[i], gpr[i]);
jit_popr(j, JIT_R0);
jit_leave_jit_abi(j, 3, 0, align);
jit_retr(j, JIT_R0);
jit_word_t (*f)(jit_word_t) = jit_end(j, NULL);
ASSERT(f(42) == 42);
}
int
main (int argc, char *argv[])
{
return main_helper(argc, argv, run_test);
}