1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 19:50:24 +02:00

Update lightening

* libguile/lightening: Merge gitlab.com/wingo/lightening/ from
  3260f7deeb.
This commit is contained in:
Andy Wingo 2020-06-12 16:17:29 +02:00
commit 3c3270491e
6 changed files with 106 additions and 50 deletions

View file

@ -1,4 +1,4 @@
image: debian:testing image: debian:stable
before_script: before_script:
- dpkg --add-architecture i386 - dpkg --add-architecture i386
@ -30,4 +30,9 @@ aarch64:
armhf: armhf:
stage: test stage: test
script: script:
- make -C tests test-armv7 CC_ARMv7=arm-linux-gnueabihf-gcc - make -C tests test-armv7 CC_ARMv7="arm-linux-gnueabihf-gcc -marm"
armhf-thumb:
stage: test
script:
- make -C tests test-armv7 CC_ARMv7="arm-linux-gnueabihf-gcc -mthumb"

View file

@ -91,6 +91,8 @@ enum jit_reloc_kind
JIT_RELOC_JCC_WITH_VENEER, JIT_RELOC_JCC_WITH_VENEER,
JIT_RELOC_LOAD_FROM_POOL, JIT_RELOC_LOAD_FROM_POOL,
#endif #endif
JIT_RELOC_MASK = 15,
JIT_RELOC_FLAG_0 = 16,
}; };
typedef struct jit_reloc typedef struct jit_reloc

View file

@ -90,9 +90,9 @@ DEFINE_ENCODER(size, 2, 22, unsigned, uint32_t)
{ \ { \
return read_signed_bitfield(*loc, kind##_width, kind##_shift); \ return read_signed_bitfield(*loc, kind##_width, kind##_shift); \
} \ } \
static int offset_in_##name##_range(ptrdiff_t diff) maybe_unused; \ static int offset_in_##name##_range(ptrdiff_t diff, int flags) maybe_unused; \
static int \ static int \
offset_in_##name##_range(ptrdiff_t diff) \ offset_in_##name##_range(ptrdiff_t diff, int flags) \
{ \ { \
return in_signed_range(diff, kind##_width); \ return in_signed_range(diff, kind##_width); \
} \ } \
@ -114,8 +114,12 @@ DEFINE_ENCODER(size, 2, 22, unsigned, uint32_t)
} \ } \
} }
DEFINE_PATCHABLE_INSTRUCTION(jmp, simm26, JMP_WITH_VENEER, 2); #define DEFINE_PATCHABLE_INSTRUCTIONS(name, kind, RELOC, rsh) \
DEFINE_PATCHABLE_INSTRUCTION(jcc, simm19, JCC_WITH_VENEER, 2); DEFINE_PATCHABLE_INSTRUCTION(name, kind, RELOC, rsh); \
DEFINE_PATCHABLE_INSTRUCTION(veneer_##name, kind, RELOC, rsh);
DEFINE_PATCHABLE_INSTRUCTIONS(jmp, simm26, JMP_WITH_VENEER, 2);
DEFINE_PATCHABLE_INSTRUCTIONS(jcc, simm19, JCC_WITH_VENEER, 2);
DEFINE_PATCHABLE_INSTRUCTION(load_from_pool, simm19, LOAD_FROM_POOL, 2); DEFINE_PATCHABLE_INSTRUCTION(load_from_pool, simm19, LOAD_FROM_POOL, 2);
struct veneer struct veneer

View file

@ -186,6 +186,8 @@
#define _NOREG (jit_gpr_regno(_PC)) #define _NOREG (jit_gpr_regno(_PC))
#define JIT_RELOC_B JIT_RELOC_FLAG_0
static void static void
emit_wide_thumb(jit_state_t *_jit, uint32_t inst) emit_wide_thumb(jit_state_t *_jit, uint32_t inst)
{ {
@ -265,9 +267,12 @@ write_wide_thumb(uint32_t *loc, uint32_t v)
} }
static int static int
offset_in_jmp_range(int32_t offset) offset_in_jmp_range(int32_t offset, int flags)
{ {
return -0x800000 <= offset && offset <= 0x7fffff; if (!(offset & 1) && flags | JIT_RELOC_B)
return 0;
else
return -0x1000000 <= offset && offset <= 0xffffff;
} }
static int32_t static int32_t
@ -287,7 +292,7 @@ decode_thumb_jump(uint32_t v)
ret |= i2 << 21; ret |= i2 << 21;
ret |= hi << 11; ret |= hi << 11;
ret |= lo; ret |= lo;
return ret; return ret << 1;
} }
static const uint32_t thumb_jump_mask = 0xf800d000; static const uint32_t thumb_jump_mask = 0xf800d000;
@ -295,14 +300,15 @@ static const uint32_t thumb_jump_mask = 0xf800d000;
static uint32_t static uint32_t
encode_thumb_jump(int32_t v) encode_thumb_jump(int32_t v)
{ {
ASSERT(offset_in_jmp_range(v)); ASSERT(offset_in_jmp_range(v, 0));
v >>= 1;
uint32_t s = !!(v & 0x800000); uint32_t s = !!(v & 0x800000);
uint32_t i1 = !!(v & 0x400000); uint32_t i1 = !!(v & 0x400000);
uint32_t i2 = !!(v & 0x200000); uint32_t i2 = !!(v & 0x200000);
uint32_t j1 = s ? i1 : !i1; uint32_t j1 = s ? i1 : !i1;
uint32_t j2 = s ? i2 : !i2; uint32_t j2 = s ? i2 : !i2;
uint32_t ret = (s<<26)|((v&0x1ff800)<<5)|(j1<<13)|(j2<<11)|(v&0x7ff); uint32_t ret = (s<<26)|((v&0x1ff800)<<5)|(j1<<13)|(j2<<11)|(v&0x7ff);
ASSERT(decode_thumb_jump(ret) == v); ASSERT(decode_thumb_jump(ret) == v << 1);
ASSERT((ret & thumb_jump_mask) == 0); ASSERT((ret & thumb_jump_mask) == 0);
return ret; return ret;
} }
@ -310,7 +316,13 @@ encode_thumb_jump(int32_t v)
static uint32_t static uint32_t
patch_thumb_jump(uint32_t inst, int32_t v) patch_thumb_jump(uint32_t inst, int32_t v)
{ {
return (inst & thumb_jump_mask) | encode_thumb_jump(v); inst &= thumb_jump_mask;
if (!(v & 1)) {
ASSERT(inst == THUMB2_BLI || inst == THUMB2_BLXI);
v = (v + 2) & ~2;
inst = THUMB2_BLXI;
}
return inst | encode_thumb_jump(v);
} }
static int32_t static int32_t
@ -325,15 +337,23 @@ patch_jmp_offset(uint32_t *loc, int32_t v)
write_wide_thumb(loc, patch_thumb_jump(read_wide_thumb(loc), v)); write_wide_thumb(loc, patch_thumb_jump(read_wide_thumb(loc), v));
} }
static void
patch_veneer_jmp_offset(uint32_t *loc, int32_t v)
{
ASSERT(!(v & 1));
patch_jmp_offset(loc, v | 1);
}
static jit_reloc_t static jit_reloc_t
emit_thumb_jump(jit_state_t *_jit, uint32_t inst) emit_thumb_jump(jit_state_t *_jit, uint32_t inst)
{ {
while (1) { while (1) {
uint8_t *pc_base = _jit->pc.uc + 4; uint8_t *pc_base = _jit->pc.uc + 4;
uint8_t rsh = 1; int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
int32_t off = (_jit->pc.uc - pc_base) >> rsh; enum jit_reloc_kind kind = JIT_RELOC_JMP_WITH_VENEER;
jit_reloc_t ret = if (inst == THUMB2_B)
jit_reloc (_jit, JIT_RELOC_JMP_WITH_VENEER, 0, _jit->pc.uc, pc_base, rsh); kind |= JIT_RELOC_B;
jit_reloc_t ret = jit_reloc (_jit, kind, 0, _jit->pc.uc, pc_base, 0);
uint8_t thumb_jump_width = 24; uint8_t thumb_jump_width = 24;
if (add_pending_literal(_jit, ret, thumb_jump_width - 1)) { if (add_pending_literal(_jit, ret, thumb_jump_width - 1)) {
emit_wide_thumb(_jit, patch_thumb_jump(inst, off)); emit_wide_thumb(_jit, patch_thumb_jump(inst, off));
@ -343,9 +363,12 @@ emit_thumb_jump(jit_state_t *_jit, uint32_t inst)
} }
static int static int
offset_in_jcc_range(int32_t v) offset_in_jcc_range(int32_t v, int flags)
{ {
return -0x80000 <= v && v <= 0x7ffff; if (!(v & 1))
return 0;
else
return -0x100000 <= v && v <= 0xfffff;
} }
static int32_t static int32_t
@ -363,7 +386,7 @@ decode_thumb_cc_jump(uint32_t v)
ret |= j1 << 17; ret |= j1 << 17;
ret |= hi << 11; ret |= hi << 11;
ret |= lo; ret |= lo;
return ret; return ret << 1;
} }
static const uint32_t thumb_cc_jump_mask = 0xfbc0d000; static const uint32_t thumb_cc_jump_mask = 0xfbc0d000;
@ -371,14 +394,15 @@ static const uint32_t thumb_cc_jump_mask = 0xfbc0d000;
static uint32_t static uint32_t
encode_thumb_cc_jump(int32_t v) encode_thumb_cc_jump(int32_t v)
{ {
ASSERT(offset_in_jcc_range(v)); ASSERT(offset_in_jcc_range(v, 0));
v >>= 1;
uint32_t s = !!(v & 0x80000); uint32_t s = !!(v & 0x80000);
uint32_t j2 = !!(v & 0x40000); uint32_t j2 = !!(v & 0x40000);
uint32_t j1 = !!(v & 0x20000); uint32_t j1 = !!(v & 0x20000);
uint32_t hi = (v >> 11) & 0x3f; uint32_t hi = (v >> 11) & 0x3f;
uint32_t lo = v & 0x7ff; uint32_t lo = v & 0x7ff;
uint32_t ret = (s<<26)|(hi << 16)|(j1<<13)|(j2<<11)|lo; uint32_t ret = (s<<26)|(hi << 16)|(j1<<13)|(j2<<11)|lo;
ASSERT(decode_thumb_cc_jump(ret) == v); ASSERT(decode_thumb_cc_jump(ret) == v << 1);
ASSERT((ret & thumb_cc_jump_mask) == 0); ASSERT((ret & thumb_cc_jump_mask) == 0);
return ret; return ret;
} }
@ -401,15 +425,21 @@ patch_jcc_offset(uint32_t *loc, int32_t v)
write_wide_thumb(loc, patch_thumb_cc_jump(read_wide_thumb(loc), v)); write_wide_thumb(loc, patch_thumb_cc_jump(read_wide_thumb(loc), v));
} }
static void
patch_veneer_jcc_offset(uint32_t *loc, int32_t v)
{
ASSERT(!(v & 1));
patch_jcc_offset(loc, v | 1);
}
static jit_reloc_t static jit_reloc_t
emit_thumb_cc_jump(jit_state_t *_jit, uint32_t inst) emit_thumb_cc_jump(jit_state_t *_jit, uint32_t inst)
{ {
while (1) { while (1) {
uint8_t *pc_base = _jit->pc.uc + 4; uint8_t *pc_base = _jit->pc.uc + 4;
uint8_t rsh = 1; int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
int32_t off = (_jit->pc.uc - pc_base) >> rsh;
jit_reloc_t ret = jit_reloc_t ret =
jit_reloc (_jit, JIT_RELOC_JCC_WITH_VENEER, 0, _jit->pc.uc, pc_base, rsh); jit_reloc (_jit, JIT_RELOC_JCC_WITH_VENEER, 0, _jit->pc.uc, pc_base, 0);
uint8_t thumb_cc_jump_width = 20; uint8_t thumb_cc_jump_width = 20;
if (add_pending_literal(_jit, ret, thumb_cc_jump_width - 1)) { if (add_pending_literal(_jit, ret, thumb_cc_jump_width - 1)) {
emit_wide_thumb(_jit, patch_thumb_cc_jump(inst, off)); emit_wide_thumb(_jit, patch_thumb_cc_jump(inst, off));
@ -1028,12 +1058,6 @@ T2_BLI(jit_state_t *_jit)
return tb(_jit, THUMB2_BLI); return tb(_jit, THUMB2_BLI);
} }
static jit_reloc_t
T2_BLXI(jit_state_t *_jit)
{
return tb(_jit, THUMB2_BLXI);
}
enum dmb_option { DMB_ISH = 0xb }; enum dmb_option { DMB_ISH = 0xb };
static void static void
T1_DMB(jit_state_t *_jit, enum dmb_option option) T1_DMB(jit_state_t *_jit, enum dmb_option option)
@ -2052,7 +2076,7 @@ rshi_u(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
static void static void
jmpr(jit_state_t *_jit, int32_t r0) jmpr(jit_state_t *_jit, int32_t r0)
{ {
T1_MOV(_jit, jit_gpr_regno(_PC), r0); T1_BX(_jit, r0);
} }
static jit_reloc_t static jit_reloc_t
@ -2064,8 +2088,6 @@ jmp(jit_state_t *_jit)
static void static void
jmpi(jit_state_t *_jit, jit_word_t i0) jmpi(jit_state_t *_jit, jit_word_t i0)
{ {
/* Strip thumb bit, if any. */
i0 &= ~1;
return jit_patch_there(_jit, jmp(_jit), (void*)i0); return jit_patch_there(_jit, jmp(_jit), (void*)i0);
} }
@ -2905,10 +2927,7 @@ callr(jit_state_t *_jit, int32_t r0)
static void static void
calli(jit_state_t *_jit, jit_word_t i0) calli(jit_state_t *_jit, jit_word_t i0)
{ {
if (i0 & 1) jit_patch_there(_jit, T2_BLI(_jit), (void*)i0);
jit_patch_there(_jit, T2_BLI(_jit), (void*)(i0 & ~1));
else
jit_patch_there(_jit, T2_BLXI(_jit), (void*)i0);
} }
static void static void
@ -2990,8 +3009,7 @@ static void
patch_jmp_without_veneer(jit_state_t *_jit, uint32_t *loc) patch_jmp_without_veneer(jit_state_t *_jit, uint32_t *loc)
{ {
uint8_t *pc_base = ((uint8_t *)loc) + 4; uint8_t *pc_base = ((uint8_t *)loc) + 4;
uint8_t rsh = 1; int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
int32_t off = (_jit->pc.uc - pc_base) >> rsh;
write_wide_thumb(loc, THUMB2_B | encode_thumb_jump(off)); write_wide_thumb(loc, THUMB2_B | encode_thumb_jump(off));
} }
@ -3014,11 +3032,10 @@ emit_veneer(jit_state_t *_jit, jit_pointer_t target)
{ {
uint16_t thumb1_ldr = 0x4800; uint16_t thumb1_ldr = 0x4800;
int32_t tmp = jit_gpr_regno(JIT_TMP1); int32_t tmp = jit_gpr_regno(JIT_TMP1);
int32_t rd = jit_gpr_regno(_PC);
ASSERT(tmp < 8); ASSERT(tmp < 8);
// Loaded addr is 4 bytes after the LDR, which is aligned, so offset is 0. // Loaded addr is 4 bytes after the LDR, which is aligned, so offset is 0.
emit_u16(_jit, thumb1_ldr | (tmp << 8)); emit_u16(_jit, thumb1_ldr | (tmp << 8));
emit_u16(_jit, THUMB_MOV|((_u4(rd)&8)<<4)|(_u4(tmp)<<3)|(rd&7)); emit_u16(_jit, THUMB_BX|(_u4(tmp)<<3));
emit_u32(_jit, (uint32_t) target); emit_u32(_jit, (uint32_t) target);
} }

View file

@ -105,11 +105,13 @@ enum guard_pool { GUARD_NEEDED, NO_GUARD_NEEDED };
static void emit_literal_pool(jit_state_t *_jit, enum guard_pool guard); static void emit_literal_pool(jit_state_t *_jit, enum guard_pool guard);
static int32_t read_jmp_offset(uint32_t *loc); static int32_t read_jmp_offset(uint32_t *loc);
static int offset_in_jmp_range(ptrdiff_t offset); static int offset_in_jmp_range(ptrdiff_t offset, int flags);
static void patch_jmp_offset(uint32_t *loc, ptrdiff_t offset); static void patch_jmp_offset(uint32_t *loc, ptrdiff_t offset);
static void patch_veneer_jmp_offset(uint32_t *loc, ptrdiff_t offset);
static int32_t read_jcc_offset(uint32_t *loc); static int32_t read_jcc_offset(uint32_t *loc);
static int offset_in_jcc_range(ptrdiff_t offset); static int offset_in_jcc_range(ptrdiff_t offset, int flags);
static void patch_jcc_offset(uint32_t *loc, ptrdiff_t offset); static void patch_jcc_offset(uint32_t *loc, ptrdiff_t offset);
static void patch_veneer_jcc_offset(uint32_t *loc, ptrdiff_t offset);
static void patch_veneer(uint32_t *loc, jit_pointer_t addr); static void patch_veneer(uint32_t *loc, jit_pointer_t addr);
static int32_t read_load_from_pool_offset(uint32_t *loc); static int32_t read_load_from_pool_offset(uint32_t *loc);
#endif #endif
@ -169,7 +171,7 @@ jit_pointer_t
jit_address(jit_state_t *_jit) jit_address(jit_state_t *_jit)
{ {
ASSERT (_jit->start); ASSERT (_jit->start);
return _jit->pc.uc; return jit_address_to_function_pointer (_jit->pc.uc);
} }
void void
@ -378,8 +380,9 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
ptrdiff_t diff = (uint8_t*)addr - pc_base; ptrdiff_t diff = (uint8_t*)addr - pc_base;
ASSERT((diff & ((1 << reloc.rsh) - 1)) == 0); ASSERT((diff & ((1 << reloc.rsh) - 1)) == 0);
diff >>= reloc.rsh; diff >>= reloc.rsh;
int flags = reloc.kind & ~JIT_RELOC_MASK;
switch (reloc.kind) switch (reloc.kind & JIT_RELOC_MASK)
{ {
case JIT_RELOC_ABSOLUTE: case JIT_RELOC_ABSOLUTE:
if (sizeof(diff) == 4) if (sizeof(diff) == 4)
@ -404,7 +407,7 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
uint8_t *target = pc_base + (voff << reloc.rsh); uint8_t *target = pc_base + (voff << reloc.rsh);
if (target == loc.uc) { if (target == loc.uc) {
// PC still in range to reify direct branch. // PC still in range to reify direct branch.
if (offset_in_jmp_range(diff)) { if (offset_in_jmp_range(diff, flags)) {
// Target also in range: reify direct branch. // Target also in range: reify direct branch.
patch_jmp_offset(loc.ui, diff); patch_jmp_offset(loc.ui, diff);
remove_pending_literal(_jit, reloc); remove_pending_literal(_jit, reloc);
@ -423,7 +426,7 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
int32_t voff = read_jcc_offset(loc.ui); int32_t voff = read_jcc_offset(loc.ui);
uint8_t *target = pc_base + (voff << reloc.rsh); uint8_t *target = pc_base + (voff << reloc.rsh);
if (target == loc.uc) { if (target == loc.uc) {
if (offset_in_jcc_range(diff)) { if (offset_in_jcc_range(diff, flags)) {
patch_jcc_offset(loc.ui, diff); patch_jcc_offset(loc.ui, diff);
remove_pending_literal(_jit, reloc); remove_pending_literal(_jit, reloc);
} else { } else {
@ -1365,13 +1368,13 @@ emit_literal_pool(jit_state_t *_jit, enum guard_pool guard)
if (_jit->overflow) if (_jit->overflow)
return; return;
switch (entry->reloc.kind) { switch (entry->reloc.kind & JIT_RELOC_MASK) {
case JIT_RELOC_JMP_WITH_VENEER: case JIT_RELOC_JMP_WITH_VENEER:
patch_jmp_offset((uint32_t*) loc, diff); patch_veneer_jmp_offset((uint32_t*) loc, diff);
emit_veneer(_jit, (void*) (uintptr_t) entry->value); emit_veneer(_jit, (void*) (uintptr_t) entry->value);
break; break;
case JIT_RELOC_JCC_WITH_VENEER: case JIT_RELOC_JCC_WITH_VENEER:
patch_jcc_offset((uint32_t*) loc, diff); patch_veneer_jcc_offset((uint32_t*) loc, diff);
emit_veneer(_jit, (void*) (uintptr_t) entry->value); emit_veneer(_jit, (void*) (uintptr_t) entry->value);
break; break;
case JIT_RELOC_LOAD_FROM_POOL: case JIT_RELOC_LOAD_FROM_POOL:

View file

@ -0,0 +1,25 @@
#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);
jit_reloc_t r = jit_jmp (j);
jit_reti (j, 0);
jit_pointer_t addr = jit_address (j);
jit_reti (j, 1);
jit_patch_here (j, r);
jit_jmpi (j, addr);
jit_reti (j, 2);
int (*f)(void) = jit_end(j, NULL);
ASSERT(f() == 1);
}
int
main (int argc, char *argv[])
{
return main_helper(argc, argv, run_test);
}