1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-04 22:40:25 +02:00

Implement the new jit_set_code interface.

* include/lightning.h, include/lightning/jit_private.h,
	lib/lightning.c: Implement the new jit_set_code() interface,
	that allows instructing lightning to use an alternate code
	buffer. The new jit_realize() function should be called
	before jit_set_code(), and usually call jit_get_code()
	to query the amount of bytes expected to be required for
	the code.

	* lib/jit_size.c: Minor update to have less chances of
	miscalculating the code buffer by starting the counter
	with the size of the longest instruction instead of zero,
	as code emit fails if at any moment less than the longest
	instruction bytes are available.

	* check/setcode.c: New file implementing some basic tests
	of the new jit_set_code() interface.

	* check/Makefile.am: Update for newer test case.
This commit is contained in:
pcpa 2014-03-11 11:40:42 -03:00
parent a9433b5a2c
commit 79bc3d03dd
9 changed files with 209 additions and 45 deletions

View file

@ -1,3 +1,24 @@
2014-11-03 Paulo Andrade <pcpa@gnu.org>
* include/lightning.h, include/lightning/jit_private.h,
lib/lightning.c: Implement the new jit_set_code() interface,
that allows instructing lightning to use an alternate code
buffer. The new jit_realize() function should be called
before jit_set_code(), and usually call jit_get_code()
to query the amount of bytes expected to be required for
the code.
* lib/jit_size.c: Minor update to have less chances of
miscalculating the code buffer by starting the counter
with the size of the longest instruction instead of zero,
as code emit fails if at any moment less than the longest
instruction bytes are available.
* check/setcode.c: New file implementing some basic tests
of the new jit_set_code() interface.
* check/Makefile.am: Update for newer test case.
2014-06-03 Paulo Andrade <pcpa@gnu.org>
* include/lightning.h, lib/lightning.c: Add the new

View file

@ -16,7 +16,7 @@
AM_CFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE
check_PROGRAMS = lightning ccall self
check_PROGRAMS = lightning ccall self setcode
lightning_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
lightning_SOURCES = lightning.c
@ -27,6 +27,9 @@ ccall_SOURCES = ccall.c
self_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
self_SOURCES = self.c
setcode_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
setcode_SOURCES = setcode.c
$(top_builddir)/lib/liblightning.la:
cd $(top_builddir)/lib; $(MAKE) $(AM_MAKEFLAGS) liblightning.la
@ -75,7 +78,6 @@ EXTRA_DIST = \
qalu_mul.tst qalu_mul.ok \
qalu_div.tst qalu_div.ok \
ret.tst ret.ok \
ccall.ok \
check.sh \
check.x87.sh \
check.arm.sh check.swf.sh \
@ -178,7 +180,7 @@ $(swf_TESTS): check.swf.sh
TESTS += $(swf_TESTS)
endif
TESTS += ccall self
TESTS += ccall self setcode
CLEANFILES = $(TESTS)
#TESTS_ENVIRONMENT=$(srcdir)/run-test;

View file

@ -1 +0,0 @@
ok

View file

@ -1 +0,0 @@
ok

89
check/setcode.c Normal file
View file

@ -0,0 +1,89 @@
/*
* Simple test of using an alternate buffer for the code.
*/
#include <lightning.h>
#include <stdio.h>
#include <assert.h>
#include <sys/mman.h>
#if defined(__sgi)
# include <fcntl.h>
#endif
#ifndef MAP_ANON
# define MAP_ANON MAP_ANONYMOUS
# ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS 0
# endif
#endif
#if !defined(__sgi)
#define mmap_fd -1
#endif
int
main(int argc, char *argv[])
{
jit_uint8_t *ptr;
jit_state_t *_jit;
jit_word_t length;
#if defined(__sgi)
int mmap_fd;
#endif
void (*function)(void);
#if defined(__sgi)
mmap_fd = open("/dev/zero", O_RDWR);
#endif
ptr = mmap(NULL, 1024 * 1024,
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
assert(ptr != MAP_FAILED);
#if defined(__sgi)
close(mmap_fd);
#endif
init_jit(argv[0]);
_jit = jit_new_state();
jit_prolog();
jit_prepare();
jit_pushargi((jit_word_t)"%s\n");
jit_ellipsis();
jit_pushargi((jit_word_t)"ok");
jit_finishi(printf);
/* call to jit_realize() is only required when using an alternate
* code buffer. Note that not using mmap'ed memory may not work
* on several ports and/or operating system versions */
jit_realize();
length = 0;
if (jit_get_code(&length) != NULL)
abort();
if (length <= 4)
abort();
/* check that a too small buffer fails */
jit_set_code(ptr, 4);
function = jit_emit();
if (function != NULL)
abort();
/* and calling again with enough space works */
jit_set_code(ptr, 1024 * 1024);
function = jit_emit();
if (function == NULL)
abort();
jit_clear_state();
(*function)();
jit_destroy_state();
finish_jit();
munmap(ptr, 1024 * 1024);
return (0);
}

View file

@ -887,6 +887,12 @@ extern void _jit_patch(jit_state_t*, jit_node_t*);
extern void _jit_patch_at(jit_state_t*, jit_node_t*, jit_node_t*);
#define jit_patch_abs(u,v) _jit_patch_abs(_jit,u,v)
extern void _jit_patch_abs(jit_state_t*, jit_node_t*, jit_pointer_t);
#define jit_realize() _jit_realize(_jit)
extern void _jit_realize(jit_state_t*);
#define jit_get_code(u) _jit_get_code(_jit,u)
extern jit_pointer_t _jit_get_code(jit_state_t*, jit_word_t*);
#define jit_set_code(u,v) _jit_set_code(_jit,u,v)
extern void _jit_set_code(jit_state_t*, jit_pointer_t, jit_word_t);
#define jit_emit() _jit_emit(_jit)
extern jit_pointer_t _jit_emit(jit_state_t*);

View file

@ -336,6 +336,7 @@ struct jit_compiler {
#endif
jit_node_t *head;
jit_node_t *tail;
jit_uint32_t realize : 1; /* jit_realize() called? */
jit_uint32_t done : 1; /* emit state finished */
jit_uint32_t emit : 1; /* emit state entered */
jit_uint32_t again : 1; /* start over emiting function */
@ -464,6 +465,8 @@ struct jit_state {
jit_word_t length;
} note;
jit_compiler_t *comp;
/* Flags to know if user did set the code and data buffers */
jit_uint32_t user_code : 1;
};
struct jit_register {

View file

@ -98,7 +98,7 @@ _jit_get_size(jit_state_t *_jit)
jit_word_t size;
jit_node_t *node;
for (size = 0, node = _jitc->head; node; node = node->next)
for (size = JIT_INSTR_MAX, node = _jitc->head; node; node = node->next)
size += _szs[node->code];
return ((size + 4095) & -4096);

View file

@ -514,7 +514,7 @@ void
_jit_save(jit_state_t *_jit, jit_int32_t reg)
{
reg = jit_regno(reg);
assert(!_jitc->emit);
assert(!_jitc->realize);
_jitc->spill[reg] = jit_new_node_w(jit_code_save, reg);
}
@ -524,7 +524,7 @@ _jit_load(jit_state_t *_jit, jit_int32_t reg)
jit_node_t *node;
reg = jit_regno(reg);
assert(!_jitc->emit);
assert(!_jitc->realize);
assert(_jitc->spill[reg]);
node = jit_new_node_w(jit_code_load, reg);
/* create a path to flag the save/load is not required */
@ -562,7 +562,7 @@ _jit_data(jit_state_t *_jit, jit_pointer_t data,
jit_word_t key;
jit_node_t *node;
assert(!_jitc->emit);
assert(!_jitc->realize);
/* Ensure there is space even if asking for a duplicate */
if (((_jitc->data.offset + 7) & -8) + length > _jit->data.length) {
@ -887,6 +887,7 @@ _jit_clear_state(jit_state_t *_jit)
void
_jit_destroy_state(jit_state_t *_jit)
{
if (!_jit->user_code)
munmap(_jit->code.ptr, _jit->code.length);
munmap(_jit->data.ptr, _jit->data.length);
jit_free((jit_pointer_t *)&_jit);
@ -895,21 +896,21 @@ _jit_destroy_state(jit_state_t *_jit)
jit_node_t *
_jit_new_node(jit_state_t *_jit, jit_code_t code)
{
assert(!_jitc->emit);
assert(!_jitc->realize);
return (link_node(new_node(code)));
}
jit_node_t *
_jit_new_node_no_link(jit_state_t *_jit, jit_code_t code)
{
assert(!_jitc->emit);
assert(!_jitc->realize);
return (new_node(code));
}
void
_jit_link_node(jit_state_t *_jit, jit_node_t *node)
{
assert(!_jitc->emit);
assert(!_jitc->realize);
link_node(node);
}
@ -918,7 +919,7 @@ _jit_new_node_w(jit_state_t *_jit, jit_code_t code,
jit_word_t u)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.w = u;
return (link_node(node));
}
@ -928,7 +929,7 @@ _jit_new_node_p(jit_state_t *_jit, jit_code_t code,
jit_pointer_t u)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.p = u;
return (link_node(node));
}
@ -938,7 +939,7 @@ _jit_new_node_ww(jit_state_t *_jit, jit_code_t code,
jit_word_t u, jit_word_t v)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.w = u;
node->v.w = v;
return (link_node(node));
@ -963,7 +964,7 @@ _jit_new_node_wf(jit_state_t *_jit, jit_code_t code,
jit_word_t u, jit_float32_t v)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.w = u;
node->v.f = v;
return (link_node(node));
@ -974,7 +975,7 @@ _jit_new_node_wd(jit_state_t *_jit, jit_code_t code,
jit_word_t u, jit_float64_t v)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.w = u;
node->v.d = v;
return (link_node(node));
@ -985,7 +986,7 @@ _jit_new_node_www(jit_state_t *_jit, jit_code_t code,
jit_word_t u, jit_word_t v, jit_word_t w)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.w = u;
node->v.w = v;
node->w.w = w;
@ -998,7 +999,7 @@ _jit_new_node_qww(jit_state_t *_jit, jit_code_t code,
jit_word_t v, jit_word_t w)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
assert(l != h);
node->u.q.l = l;
node->u.q.h = h;
@ -1012,7 +1013,7 @@ _jit_new_node_wwf(jit_state_t *_jit, jit_code_t code,
jit_word_t u, jit_word_t v, jit_float32_t w)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.w = u;
node->v.w = v;
node->w.f = w;
@ -1024,7 +1025,7 @@ _jit_new_node_wwd(jit_state_t *_jit, jit_code_t code,
jit_word_t u, jit_word_t v, jit_float64_t w)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.w = u;
node->v.w = v;
node->w.d = w;
@ -1036,7 +1037,7 @@ _jit_new_node_pww(jit_state_t *_jit, jit_code_t code,
jit_pointer_t u, jit_word_t v, jit_word_t w)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.p = u;
node->v.w = v;
node->w.w = w;
@ -1048,7 +1049,7 @@ _jit_new_node_pwf(jit_state_t *_jit, jit_code_t code,
jit_pointer_t u, jit_word_t v, jit_float32_t w)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.p = u;
node->v.w = v;
node->w.f = w;
@ -1060,7 +1061,7 @@ _jit_new_node_pwd(jit_state_t *_jit, jit_code_t code,
jit_pointer_t u, jit_word_t v, jit_float64_t w)
{
jit_node_t *node = new_node(code);
assert(!_jitc->emit);
assert(!_jitc->realize);
node->u.p = u;
node->v.w = v;
node->w.d = w;
@ -1703,6 +1704,49 @@ _jit_regarg_clr(jit_state_t *_jit, jit_node_t *node, jit_int32_t value)
jit_regset_clrbit(&_jitc->regarg, jit_regno(node->w.w));
}
void
_jit_realize(jit_state_t *_jit)
{
assert(!_jitc->realize);
if (_jitc->function)
jit_epilog();
jit_optimize();
_jitc->realize = 1;
#if GET_JIT_SIZE
/* Heuristic to guess code buffer size */
_jitc->mult = 4;
_jit->code.length = _jitc->pool.length * 1024 * _jitc->mult;
#else
_jit->code.length = jit_get_size();
#endif
}
jit_pointer_t
_jit_get_code(jit_state_t *_jit, jit_word_t *length)
{
assert(_jitc->realize);
if (length) {
if (_jitc->done)
/* If code already generated, return exact size of code */
*length = _jit->pc.uc - _jit->code.ptr;
else
/* Else return current size of the code buffer */
*length = _jit->code.length;
}
return (_jit->code.ptr);
}
void
_jit_set_code(jit_state_t *_jit, jit_pointer_t ptr, jit_word_t length)
{
assert(_jitc->realize);
_jit->code.ptr = ptr;
_jit->code.length = length;
_jit->user_code = 1;
}
jit_pointer_t
_jit_emit(jit_state_t *_jit)
{
@ -1714,20 +1758,12 @@ _jit_emit(jit_state_t *_jit)
int mmap_fd;
#endif
if (_jitc->function)
jit_epilog();
jit_optimize();
if (!_jitc->realize)
jit_realize();
_jitc->emit = 1;
#if GET_JIT_SIZE
/* Heuristic to guess code buffer size */
_jitc->mult = 4;
_jit->code.length = _jitc->pool.length * 1024 * _jitc->mult;
#else
_jit->code.length = jit_get_size();
#endif
if (!_jit->user_code) {
#if defined(__sgi)
mmap_fd = open("/dev/zero", O_RDWR);
#endif
@ -1735,18 +1771,22 @@ _jit_emit(jit_state_t *_jit)
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
assert(_jit->code.ptr != MAP_FAILED);
}
_jitc->code.end = _jit->code.ptr + _jit->code.length -
jit_get_max_instr();
_jit->pc.uc = _jit->code.ptr;
for (;;) {
if ((code = emit_code()) == NULL) {
_jitc->patches.offset = 0;
for (node = _jitc->head; node; node = node->next) {
if (node->link &&
(node->code == jit_code_label ||
node->code == jit_code_epilog))
node->flag &= ~jit_flag_patch;
}
if (_jit->user_code)
goto fail;
#if GET_JIT_SIZE
++_jitc->mult;
length = _jitc->pool.length * 1024 * _jitc->mult;
@ -1778,13 +1818,13 @@ _jit_emit(jit_state_t *_jit)
_jitc->code.end = _jit->code.ptr + _jit->code.length -
jit_get_max_instr();
_jit->pc.uc = _jit->code.ptr;
_jitc->patches.offset = 0;
}
else
break;
}
#if defined(__sgi)
if (!_jit->user_code)
close(mmap_fd);
#endif
@ -1793,10 +1833,15 @@ _jit_emit(jit_state_t *_jit)
result = mprotect(_jit->data.ptr, _jit->data.length, PROT_READ);
assert(result == 0);
result = mprotect(_jit->code.ptr, _jit->code.length, PROT_READ | PROT_EXEC);
if (!_jit->user_code) {
result = mprotect(_jit->code.ptr, _jit->code.length,
PROT_READ | PROT_EXEC);
assert(result == 0);
}
return (_jit->code.ptr);
fail:
return (NULL);
}
/* Compute initial reglive and regmask set values of a basic block.