1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-14 17:50:22 +02:00

Implementation of new design

Documentation to come, as tests get added and things settle down.
This commit is contained in:
Andy Wingo 2019-03-22 15:20:40 +01:00
parent 0d81c5c337
commit bad7e34c83
18 changed files with 4333 additions and 7149 deletions

491
jit/jit.c
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.
*
@ -14,7 +14,7 @@
* License for more details.
*
* Authors:
* Paulo Cesar Pereira de Andrade
* Paulo Cesar Pereira de Andrade
*/
#if HAVE_CONFIG_H
@ -30,107 +30,118 @@
#include "../jit.h"
#if defined(__GNUC__)
# define maybe_unused __attribute__ ((unused))
# define maybe_unused __attribute__ ((unused))
#else
# define maybe_unused /**/
# define maybe_unused /**/
#endif
#define rc(value) jit_class_##value
#define rn(reg) (jit_regno(_rvs[jit_regno(reg)].spec))
#define rc(value) jit_class_##value
#define rn(reg) (jit_regno(_rvs[jit_regno(reg)].spec))
#if defined(__i386__) || defined(__x86_64__)
# define JIT_SP _RSP
# define JIT_RET _RAX
# if __X32
# define JIT_FRET _ST0
# define JIT_SP _RSP
# define JIT_RET _RAX
# if __X32
# define JIT_FRET _ST0
# else
# if __CYGWIN__
# define JIT_RA0 _RCX
# else
# if __CYGWIN__
# define JIT_RA0 _RCX
# else
# define JIT_RA0 _RDI
# endif
# define JIT_FA0 _XMM0
# define JIT_FRET _XMM0
# define JIT_RA0 _RDI
# endif
# define JIT_FA0 _XMM0
# define JIT_FRET _XMM0
# endif
#elif defined(__mips__)
# define JIT_RA0 _A0
# define JIT_FA0 _F12
# define JIT_SP _SP
# define JIT_RET _V0
# define JIT_FRET _F0
# define JIT_RA0 _A0
# define JIT_FA0 _F12
# define JIT_SP _SP
# define JIT_RET _V0
# define JIT_FRET _F0
#elif defined(__arm__)
# define JIT_RA0 _R0
# define JIT_FA0 _D0
# define JIT_SP _R13
# define JIT_RET _R0
# if defined(__ARM_PCS_VFP)
# define JIT_FRET _D0
# else
# define JIT_FRET _R0
# endif
# define JIT_RA0 _R0
# define JIT_FA0 _D0
# define JIT_SP _R13
# define JIT_RET _R0
# if defined(__ARM_PCS_VFP)
# define JIT_FRET _D0
# else
# define JIT_FRET _R0
# endif
#elif defined(__ppc__) || defined(__powerpc__)
# define JIT_RA0 _R3
# define JIT_FA0 _F1
# define JIT_SP _R1
# define JIT_RET _R3
# define JIT_FRET _F1
# define JIT_RA0 _R3
# define JIT_FA0 _F1
# define JIT_SP _R1
# define JIT_RET _R3
# define JIT_FRET _F1
#elif defined(__sparc__)
# define JIT_SP _SP
# define JIT_RET _I0
# define JIT_FRET _F0
# define JIT_SP _SP
# define JIT_RET _I0
# define JIT_FRET _F0
#elif defined(__ia64__)
# define JIT_SP _R12
# define JIT_RET _R8
# define JIT_FRET _F8
# define JIT_SP _R12
# define JIT_RET _R8
# define JIT_FRET _F8
#elif defined(__hppa__)
# define JIT_SP _R30
# define JIT_RET _R28
# define JIT_FRET _F4
# define JIT_SP _R30
# define JIT_RET _R28
# define JIT_FRET _F4
#elif defined(__aarch64__)
# define JIT_RA0 _R0
# define JIT_FA0 _V0
# define JIT_SP _SP
# define JIT_RET _R0
# define JIT_FRET _V0
# define JIT_RA0 _R0
# define JIT_FA0 _V0
# define JIT_SP _SP
# define JIT_RET _R0
# define JIT_FRET _V0
#elif defined(__s390__) || defined(__s390x__)
# define JIT_SP _R15
# define JIT_RET _R2
# define JIT_FRET _F0
# define JIT_SP _R15
# define JIT_RET _R2
# define JIT_FRET _F0
#elif defined(__alpha__)
# define JIT_SP _SP
# define JIT_RET _V0
# define JIT_FRET _F0
# define JIT_SP _SP
# define JIT_RET _V0
# define JIT_FRET _F0
#endif
/*
* Private jit_class bitmasks
*/
#define jit_class_named 0x00400000 /* hit must be the named reg */
#define jit_class_nospill 0x00800000 /* hint to fail if need spill */
#define jit_class_sft 0x01000000 /* not a hardware register */
#define jit_class_rg8 0x04000000 /* x86 8 bits */
#define jit_class_xpr 0x80000000 /* float / vector */
#define jit_class_named 0x00400000 /* hit must be the named reg */
#define jit_class_nospill 0x00800000 /* hint to fail if need spill */
#define jit_class_sft 0x01000000 /* not a hardware register */
#define jit_class_rg8 0x04000000 /* x86 8 bits */
#define jit_class_xpr 0x80000000 /* float / vector */
/* Used on sparc64 where %f0-%f31 can be encode for single float
* but %f32 to %f62 only as double precision */
#define jit_class_sng 0x10000000 /* Single precision float */
#define jit_class_dbl 0x20000000 /* Only double precision float */
#define jit_regno_patch 0x00008000 /* this is a register
* returned by a "user" call
* to jit_get_reg() */
#define jit_class_sng 0x10000000 /* Single precision float */
#define jit_class_dbl 0x20000000 /* Only double precision float */
#define jit_regno_patch 0x00008000 /* this is a register
* returned by a "user" call
* to jit_get_reg() */
union jit_pc
{
uint8_t *uc;
uint16_t *us;
uint32_t *ui;
uint64_t *ul;
intptr_t w;
uintptr_t uw;
};
struct jit_state
{
union {
uint8_t *uc;
uint16_t *us;
uint32_t *ui;
uint64_t *ul;
intptr_t w;
uintptr_t uw;
} pc;
union jit_pc pc;
uint8_t *start;
uint8_t *last_instruction_start;
uint8_t *limit;
uint8_t temp_gpr_saved;
uint8_t temp_fpr_saved;
uint8_t overflow;
};
enum jit_reloc_flags
{
JIT_RELOC_CAN_SHORTEN = 1<<0
};
struct jit_register
@ -143,45 +154,40 @@ typedef struct jit_register jit_register_t;
static const jit_register_t _rvs[];
#define jit_regload_reload 0 /* convert to reload */
#define jit_regload_delete 1 /* just remove node */
#define jit_regload_isdead 2 /* delete and unset live bit */
#define jit_regload_reload 0 /* convert to reload */
#define jit_regload_delete 1 /* just remove node */
#define jit_regload_isdead 2 /* delete and unset live bit */
#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 inline uint8_t*
jit_reloc_instruction (jit_reloc_t reloc)
{
return (uint8_t*) reloc;
}
static void jit_get_cpu(void);
static void jit_init(jit_state_t *);
static void jit_nop(jit_state_t *, unsigned);
static void jit_patch(jit_state_t *, const uint8_t *loc, const uint8_t *addr);
static void jit_patch_last(jit_state_t *, const uint8_t *loc, const uint8_t *addr);
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);
void
jit_bool_t
init_jit(void)
{
jit_get_cpu();
return jit_get_cpu ();
}
jit_state_t *
jit_new_state(void)
{
jit_state_t *_jit;
jit_state_t *_jit = malloc (sizeof (*_jit));
if (!_jit)
abort ();
_jit = malloc (sizeof (*_jit));
if (!_jit)
abort ();
memset(_jit, 0, sizeof (*_jit));
memset(_jit, 0, sizeof (*_jit));
if (!jit_init (_jit));
jit_init (_jit);
return _jit;
return _jit;
}
void
@ -193,36 +199,44 @@ jit_destroy_state(jit_state_t *_jit)
jit_pointer_t
jit_address(jit_state_t *_jit)
{
/* TODO: FIXME */
abort ();
return _jit->pc.uc;
}
void
jit_begin(jit_state_t *_jit, jit_addr_t addr, size_t length)
jit_begin(jit_state_t *_jit, uint8_t* buf, size_t length)
{
ASSERT (!_jit->start);
_jit->start = addr;
_jit->limit = _jit->start + length;
_jit->start = buf;
_jit->limit = buf + length;
jit_reset(_jit);
}
jit_bool_t
jit_has_overflow(jit_state_t *_jit)
{
ASSERT (_jit->start);
return _jit->overflow;
}
void
jit_reset(jit_state_t *_jit)
{
ASSERT (_jit->start);
_jit->pc.uc = _jit->start = _jit->limit = NULL;
_jit->pc.uc = _jit->start;
_jit->overflow = 0;
}
jit_addr_t
void*
jit_end(jit_state_t *_jit, size_t *length)
{
uint8_t *code = _jit->start;
uint8_t *end = _jit->pc.uc;
ASSERT (code);
ASSERT (end > code);
ASSERT (code <= end);
ASSERT (end <= _jit->limit);
ASSERT (!_jit->overflow);
jit_flush (code, end);
@ -230,7 +244,8 @@ jit_end(jit_state_t *_jit, size_t *length)
*length = end - code;
}
jit_reset (_jit);
_jit->pc.uc = _jit->start = _jit->limit = NULL;
_jit->overflow = 0;
return code;
}
@ -251,6 +266,79 @@ jit_align(jit_state_t *_jit, unsigned align)
jit_nop(_jit, there - here);
}
static inline void emit_u8(jit_state_t *_jit, uint8_t u8) {
if (UNLIKELY(_jit->pc.uc + 1 > _jit->limit)) {
_jit->overflow = 1;
} else {
*_jit->pc.uc++ = u8;
}
}
static inline void emit_u16(jit_state_t *_jit, uint16_t u16) {
if (UNLIKELY(_jit->pc.us + 1 > (uint16_t*)_jit->limit)) {
_jit->overflow = 1;
} else {
*_jit->pc.us++ = u16;
}
}
static inline void emit_u32(jit_state_t *_jit, uint32_t u32) {
if (UNLIKELY(_jit->pc.ui + 1 > (uint32_t*)_jit->limit)) {
_jit->overflow = 1;
} else {
*_jit->pc.ui++ = u32;
}
}
static inline void emit_u64(jit_state_t *_jit, uint64_t u64) {
if (UNLIKELY(_jit->pc.ul + 1 > (uint64_t*)_jit->limit)) {
_jit->overflow = 1;
} else {
*_jit->pc.ul++ = u64;
}
}
static inline jit_reloc_t
jit_reloc (jit_state_t *_jit, enum jit_reloc_kind kind,
uint8_t inst_start_offset, uint16_t flags, intptr_t addend)
{
jit_reloc_t ret;
ret.kind = kind;
ret.inst_start_offset = inst_start_offset;
ret.flags = 0;
ret.offset = _jit->pc.uc - _jit->start;
switch (kind)
{
case JIT_RELOC_ABSOLUTE:
if (sizeof(intptr_t) == 4)
emit_u32 (_jit, addend);
else
emit_u64 (_jit, addend);
break;
case JIT_RELOC_REL8:
ASSERT (INT8_MIN <= addend && addend <= INT8_MAX);
emit_u8 (_jit, addend - 1);
break;
case JIT_RELOC_REL16:
ASSERT (INT16_MIN <= addend && addend <= INT16_MAX);
emit_u16 (_jit, addend - 2);
break;
case JIT_RELOC_REL32:
ASSERT (INT32_MIN <= addend && addend <= INT32_MAX);
emit_u32 (_jit, addend - 4);
break;
case JIT_RELOC_REL64:
emit_u64 (_jit, addend - 8);
break;
default:
abort ();
}
return ret;
}
void
jit_patch_here(jit_state_t *_jit, jit_reloc_t reloc)
{
@ -260,82 +348,145 @@ jit_patch_here(jit_state_t *_jit, jit_reloc_t reloc)
void
jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
{
const uint8_t *loc = jit_reloc_instruction (reloc);
if (_jit->overflow)
return;
union jit_pc loc;
loc.uc = _jit->start + reloc.offset;
ptrdiff_t diff = addr - ((void*) 0);
if (loc == _jit->last_instruction_start)
jit_patch_last (_jit, loc, addr);
else
jit_patch (_jit, loc, addr);
switch (reloc.kind)
{
case JIT_RELOC_ABSOLUTE:
if (sizeof(diff) == 4)
*loc.ui = diff + (int32_t)*loc.ui;
else
*loc.ul = diff + (int64_t)*loc.ul;
if (loc.uc + sizeof(diff) == _jit->pc.uc &&
(reloc.flags & JIT_RELOC_CAN_SHORTEN))
jit_try_shorten (_jit, reloc);
break;
case JIT_RELOC_REL8:
diff += (int8_t)*loc.uc;
ASSERT (INT8_MIN <= diff && diff <= INT8_MAX);
*loc.uc = diff;
break;
case JIT_RELOC_REL16:
diff += (int16_t)*loc.us;
ASSERT (INT16_MIN <= diff && diff <= INT16_MAX);
*loc.us = diff;
if ((loc.uc + 1) == _jit->pc.uc && (reloc.flags & JIT_RELOC_CAN_SHORTEN))
jit_try_shorten (_jit, reloc);
break;
case JIT_RELOC_REL32:
diff += (int32_t)*loc.ui;
ASSERT (INT32_MIN <= diff && diff <= INT32_MAX);
*loc.ui = diff;
if ((loc.ui + 1) == _jit->pc.ui && (reloc.flags & JIT_RELOC_CAN_SHORTEN))
jit_try_shorten (_jit, reloc);
break;
case JIT_RELOC_REL64:
*loc.ul = diff + (int64_t)*loc.ul;
if ((loc.ul + 1) == _jit->pc.ul && (reloc.flags & JIT_RELOC_CAN_SHORTEN))
jit_try_shorten (_jit, reloc);
break;
default:
abort ();
}
}
#if defined(__i386__) || defined(__x86_64__)
# include "x86.c"
# include "x86.c"
#elif defined(__mips__)
# include "mips.c"
# include "mips.c"
#elif defined(__arm__)
# include "arm.c"
# include "arm.c"
#elif defined(__ppc__) || defined(__powerpc__)
# include "ppc.c"
# include "ppc.c"
#elif defined(__sparc__)
# include "sparc.c"
# include "sparc.c"
#elif defined(__ia64__)
# include "ia64.c"
# include "ia64.c"
#elif defined(__hppa__)
# include "hppa.c"
# include "hppa.c"
#elif defined(__aarch64__)
# include "aarch64.c"
# include "aarch64.c"
#elif defined(__s390__) || defined(__s390x__)
# include "s390.c"
# include "s390.c"
#elif defined(__alpha__)
# include "alpha.c"
# include "alpha.c"
#endif
#define JIT_CALL_0(stem) _jit_##stem (_jit)
#define JIT_CALL_1(stem) _jit_##stem (_jit, a)
#define JIT_CALL_2(stem) _jit_##stem (_jit, a, b)
#define JIT_CALL_3(stem) _jit_##stem (_jit, a, b, c)
#define JIT_CALL_4(stem) _jit_##stem (_jit, a, b, c, d)
#define JIT_TAIL_CALL_RFF__(stem) return JIT_CALL_2(stem)
#define JIT_TAIL_CALL_RGG__(stem) return JIT_CALL_2(stem)
#define JIT_TAIL_CALL_RG___(stem) return JIT_CALL_1(stem)
#define JIT_TAIL_CALL_RGi__(stem) return JIT_CALL_2(stem)
#define JIT_TAIL_CALL_RGu__(stem) return JIT_CALL_2(stem)
#define JIT_TAIL_CALL_R____(stem) return JIT_CALL_0(stem)
#define JIT_TAIL_CALL__FFF_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__FF__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__FGG_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__FG__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__FGo_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__F___(stem) JIT_CALL_1(stem)
#define JIT_TAIL_CALL__Fd__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__Ff__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__Fp__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__GF__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__GGF_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__GGGG(stem) JIT_CALL_4(stem)
#define JIT_TAIL_CALL__GGG_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__GGGi(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__GGGu(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__GG__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__GGi_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__GGo_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__GGu_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__G___(stem) JIT_CALL_1(stem)
#define JIT_TAIL_CALL__Gi__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__Gp__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL______(stem) JIT_CALL_0(stem)
#define JIT_TAIL_CALL__i___(stem) JIT_CALL_1(stem)
#define JIT_TAIL_CALL__oGF_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__oGG_(stem) JIT_CALL_3(stem)
#define JIT_TAIL_CALL__pF__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__pG__(stem) JIT_CALL_2(stem)
#define JIT_TAIL_CALL__p___(stem) JIT_CALL_1(stem)
#define DEFINE_INSTRUCTION(kind, stem) \
JIT_PROTO_##kind(stem) \
{ \
JIT_TAIL_CALL_##kind(stem); \
#define JIT_IMPL_0(stem, ret) \
ret jit_##stem (jit_state_t* _jit) \
{ \
return stem(_jit); \
}
FOR_EACH_INSTRUCTION(DEFINE_INSTRUCTION)
#undef DEFINE_INSTRUCTION
#define JIT_IMPL_1(stem, ret, ta) \
ret jit_##stem (jit_state_t* _jit, jit_##ta##_t a) \
{ \
return stem(_jit, unwrap_##ta(a)); \
}
#define JIT_IMPL_2(stem, ret, ta, tb) \
ret jit_##stem (jit_state_t* _jit, jit_##ta##_t a, jit_##tb##_t b) \
{ \
return stem(_jit, unwrap_##ta(a), unwrap_##tb(b)); \
}
#define JIT_IMPL_3(stem, ret, ta, tb, tc) \
ret jit_##stem (jit_state_t* _jit, jit_##ta##_t a, jit_##tb##_t b, jit_##tc##_t c) \
{ \
return stem(_jit, unwrap_##ta(a), unwrap_##tb(b), unwrap_##tc(c)); \
}
#define JIT_IMPL_4(stem, ret, ta, tb, tc, td) \
ret jit_##stem (jit_state_t* _jit, jit_##ta##_t a, jit_##tb##_t b, jit_##tc##_t c, jit_##td##_t d) \
{ \
return stem(_jit, unwrap_##ta(a), unwrap_##tb(b), unwrap_##tc(c), unwrap_##td(d)); \
}
#define JIT_IMPL_RFF__(stem) JIT_IMPL_2(stem, jit_reloc_t, fpr, fpr)
#define JIT_IMPL_RGG__(stem) JIT_IMPL_2(stem, jit_reloc_t, gpr, gpr)
#define JIT_IMPL_RG___(stem) JIT_IMPL_1(stem, jit_reloc_t, gpr)
#define JIT_IMPL_RGi__(stem) JIT_IMPL_2(stem, jit_reloc_t, gpr, imm)
#define JIT_IMPL_RGu__(stem) JIT_IMPL_2(stem, jit_reloc_t, gpr, uimm)
#define JIT_IMPL_R____(stem) JIT_IMPL_0(stem, jit_reloc_t)
#define JIT_IMPL__FFF_(stem) JIT_IMPL_3(stem, void, fpr, fpr, fpr)
#define JIT_IMPL__FF__(stem) JIT_IMPL_2(stem, void, fpr, fpr)
#define JIT_IMPL__FGG_(stem) JIT_IMPL_3(stem, void, fpr, gpr, gpr)
#define JIT_IMPL__FG__(stem) JIT_IMPL_2(stem, void, fpr, gpr)
#define JIT_IMPL__FGo_(stem) JIT_IMPL_3(stem, void, fpr, gpr, off)
#define JIT_IMPL__F___(stem) JIT_IMPL_1(stem, void, fpr)
#define JIT_IMPL__Fd__(stem) JIT_IMPL_2(stem, void, fpr, float64)
#define JIT_IMPL__Ff__(stem) JIT_IMPL_2(stem, void, fpr, float32)
#define JIT_IMPL__Fp__(stem) JIT_IMPL_2(stem, void, fpr, pointer)
#define JIT_IMPL__GF__(stem) JIT_IMPL_2(stem, void, gpr, fpr)
#define JIT_IMPL__GGF_(stem) JIT_IMPL_3(stem, void, gpr, gpr, fpr)
#define JIT_IMPL__GGGG(stem) JIT_IMPL_4(stem, void, gpr, gpr, gpr, gpr)
#define JIT_IMPL__GGG_(stem) JIT_IMPL_3(stem, void, gpr, gpr, gpr)
#define JIT_IMPL__GGGi(stem) JIT_IMPL_4(stem, void, gpr, gpr, gpr, imm)
#define JIT_IMPL__GGGu(stem) JIT_IMPL_4(stem, void, gpr, gpr, gpr, uimm)
#define JIT_IMPL__GG__(stem) JIT_IMPL_2(stem, void, gpr, gpr)
#define JIT_IMPL__GGi_(stem) JIT_IMPL_3(stem, void, gpr, gpr, imm)
#define JIT_IMPL__GGo_(stem) JIT_IMPL_3(stem, void, gpr, gpr, off)
#define JIT_IMPL__GGu_(stem) JIT_IMPL_3(stem, void, gpr, gpr, uimm)
#define JIT_IMPL__G___(stem) JIT_IMPL_1(stem, void, gpr)
#define JIT_IMPL__Gi__(stem) JIT_IMPL_2(stem, void, gpr, imm)
#define JIT_IMPL__Gp__(stem) JIT_IMPL_2(stem, void, gpr, pointer)
#define JIT_IMPL______(stem) JIT_IMPL_0(stem, void)
#define JIT_IMPL__i___(stem) JIT_IMPL_1(stem, void, imm)
#define JIT_IMPL__oGF_(stem) JIT_IMPL_3(stem, void, off, gpr, fpr)
#define JIT_IMPL__oGG_(stem) JIT_IMPL_3(stem, void, off, gpr, gpr)
#define JIT_IMPL__pF__(stem) JIT_IMPL_2(stem, void, pointer, fpr)
#define JIT_IMPL__pG__(stem) JIT_IMPL_2(stem, void, pointer, gpr)
#define JIT_IMPL__p___(stem) JIT_IMPL_1(stem, void, pointer)
#define unwrap_gpr(r) rn(r)
#define unwrap_fpr(r) rn(r)
#define unwrap_imm(i) i
#define unwrap_uimm(u) u
#define unwrap_off(o) o
#define unwrap_pointer(p) ((uintptr_t) p)
#define unwrap_float32(f) f
#define unwrap_float64(d) d
#define IMPL_INSTRUCTION(kind, stem) JIT_IMPL_##kind(stem)
FOR_EACH_INSTRUCTION(IMPL_INSTRUCTION)
#undef IMPL_INSTRUCTION