summaryrefslogtreecommitdiff
path: root/src/runtime/c/pgf/jit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/c/pgf/jit.c')
-rw-r--r--src/runtime/c/pgf/jit.c386
1 files changed, 311 insertions, 75 deletions
diff --git a/src/runtime/c/pgf/jit.c b/src/runtime/c/pgf/jit.c
index 250b5a3a6..ba7788a1a 100644
--- a/src/runtime/c/pgf/jit.c
+++ b/src/runtime/c/pgf/jit.c
@@ -1,23 +1,22 @@
#include <gu/seq.h>
#include <gu/file.h>
#include <pgf/data.h>
-#include <pgf/jit.h>
#include <pgf/reasoner.h>
+#include <pgf/evaluator.h>
+#include <pgf/reader.h>
#include "lightning.h"
//#define PGF_JIT_DEBUG
struct PgfJitState {
- GuPool* tmp_pool;
- GuPool* pool;
jit_state jit;
jit_insn *buf;
char *save_ip_ptr;
GuBuf* patches;
};
-#define _jit (state->jit)
+#define _jit (rdr->jit_state->jit)
typedef struct {
PgfCId cid;
@@ -27,7 +26,7 @@ typedef struct {
// Between two calls to pgf_jit_make_space we are not allowed
// to emit more that JIT_CODE_WINDOW bytes. This is not quite
// safe but this is how GNU lightning is designed.
-#define JIT_CODE_WINDOW 128
+#define JIT_CODE_WINDOW 1280
typedef struct {
GuFinalizer fin;
@@ -42,7 +41,7 @@ pgf_jit_finalize_page(GuFinalizer* self)
}
static void
-pgf_jit_alloc_page(PgfJitState* state)
+pgf_jit_alloc_page(PgfReader* rdr)
{
void *page;
@@ -58,46 +57,63 @@ pgf_jit_alloc_page(PgfJitState* state)
gu_fatal("Memory allocation failed");
}
- PgfPageFinalizer* fin = gu_new(PgfPageFinalizer, state->pool);
+ PgfPageFinalizer* fin =
+ gu_new(PgfPageFinalizer, rdr->opool);
fin->fin.fn = pgf_jit_finalize_page;
fin->page = page;
- gu_pool_finally(state->pool, &fin->fin);
+ gu_pool_finally(rdr->opool, &fin->fin);
- state->buf = page;
- jit_set_ip(state->buf);
+ rdr->jit_state->buf = page;
+ jit_set_ip(rdr->jit_state->buf);
}
PgfJitState*
-pgf_jit_init(GuPool* tmp_pool, GuPool* pool)
+pgf_new_jit(PgfReader* rdr)
{
- PgfJitState* state = gu_new(PgfJitState, tmp_pool);
- state->tmp_pool = tmp_pool;
- state->pool = pool;
- state->patches = gu_new_buf(PgfCallPatch, tmp_pool);
-
- pgf_jit_alloc_page(state);
- state->save_ip_ptr = jit_get_ip().ptr;
-
+ PgfJitState* state = gu_new(PgfJitState, rdr->tmp_pool);
+ state->patches = gu_new_buf(PgfCallPatch, rdr->tmp_pool);
+ state->buf = NULL;
+ state->save_ip_ptr = NULL;
return state;
}
static void
-pgf_jit_make_space(PgfJitState* state)
+pgf_jit_make_space(PgfReader* rdr)
{
- assert (state->save_ip_ptr + JIT_CODE_WINDOW > jit_get_ip().ptr);
-
size_t page_size = getpagesize();
- if (jit_get_ip().ptr + JIT_CODE_WINDOW > ((char*) state->buf) + page_size) {
- jit_flush_code(state->buf, jit_get_ip().ptr);
- pgf_jit_alloc_page(state);
+ if (rdr->jit_state->buf == NULL) {
+ pgf_jit_alloc_page(rdr);
+ } else {
+ assert (rdr->jit_state->save_ip_ptr + JIT_CODE_WINDOW > jit_get_ip().ptr);
+
+ if (jit_get_ip().ptr + JIT_CODE_WINDOW > ((char*) rdr->jit_state->buf) + page_size) {
+ jit_flush_code(rdr->jit_state->buf, jit_get_ip().ptr);
+ pgf_jit_alloc_page(rdr);
+ }
}
+
+ rdr->jit_state->save_ip_ptr = jit_get_ip().ptr;
+}
+
+static PgfAbsFun*
+pgf_jit_read_absfun(PgfReader* rdr, PgfAbstr* abstr)
+{
+ gu_in_f64be(rdr->in, rdr->err); // ignore
+ gu_return_on_exn(rdr->err, NULL);
+
+ PgfCId name = pgf_read_cid(rdr, rdr->tmp_pool);
+ gu_return_on_exn(rdr->err, NULL);
+
+ PgfAbsFun* absfun =
+ gu_map_get(abstr->funs, name, PgfAbsFun*);
+ assert(absfun != NULL);
- state->save_ip_ptr = jit_get_ip().ptr;
+ return absfun;
}
void
-pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
- PgfAbsCat* abscat, GuBuf* functions)
+pgf_jit_predicate(PgfReader* rdr, PgfAbstr* abstr,
+ PgfAbsCat* abscat)
{
#ifdef PGF_JIT_DEBUG
GuPool* tmp_pool = gu_new_pool();
@@ -110,21 +126,24 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
int label = 0;
#endif
- size_t n_funs = gu_buf_length(functions);
-
- pgf_jit_make_space(state);
+ size_t n_funs = pgf_read_len(rdr);
+ gu_return_on_exn(rdr->err, );
+
+ pgf_jit_make_space(rdr);
abscat->predicate = (PgfPredicate) jit_get_ip().ptr;
jit_prolog(2);
+ PgfAbsFun* absfun = NULL;
+ PgfAbsFun* next_absfun = NULL;
+
if (n_funs > 0) {
- PgfAbsFun* absfun =
- gu_buf_get(functions, PgfAbsFun*, 0);
+ next_absfun = pgf_jit_read_absfun(rdr, abstr);
#ifdef PGF_JIT_DEBUG
gu_puts(" TRY_FIRST ", out, err);
- gu_string_write(absfun->name, out, err);
+ gu_string_write(next_absfun->name, out, err);
gu_puts("\n", out, err);
#endif
@@ -135,7 +154,7 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
// compile TRY_FIRST
jit_prepare(3);
- jit_movi_p(JIT_V0,absfun);
+ jit_movi_p(JIT_V0,next_absfun);
jit_pusharg_p(JIT_V0);
jit_pusharg_p(JIT_V2);
jit_pusharg_p(JIT_V1);
@@ -150,20 +169,15 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
#ifdef PGF_JIT_DEBUG
if (n_funs > 0) {
- PgfAbsFun* absfun =
- gu_buf_get(functions, PgfAbsFun*, 0);
-
- gu_string_write(absfun->name, out, err);
+ gu_string_write(next_absfun->name, out, err);
gu_puts(":\n", out, err);
}
#endif
for (size_t i = 0; i < n_funs; i++) {
- PgfAbsFun* absfun =
- gu_buf_get(functions, PgfAbsFun*, i);
-
- pgf_jit_make_space(state);
+ pgf_jit_make_space(rdr);
+ absfun = next_absfun;
absfun->predicate = (PgfPredicate) jit_get_ip().ptr;
jit_prolog(2);
@@ -176,18 +190,17 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
if (n_hypos > 0) {
if (i+1 < n_funs) {
- PgfAbsFun* absfun =
- gu_buf_get(functions, PgfAbsFun*, i+1);
+ next_absfun = pgf_jit_read_absfun(rdr, abstr); // i+1
#ifdef PGF_JIT_DEBUG
gu_puts(" TRY_ELSE ", out, err);
- gu_string_write(absfun->name, out, err);
+ gu_string_write(next_absfun->name, out, err);
gu_puts("\n", out, err);
#endif
// compile TRY_ELSE
jit_prepare(3);
- jit_movi_p(JIT_V0, absfun);
+ jit_movi_p(JIT_V0, next_absfun);
jit_pusharg_p(JIT_V0);
jit_pusharg_p(JIT_V2);
jit_pusharg_p(JIT_V1);
@@ -200,9 +213,6 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
jit_insn *ref;
// call the predicate for the category in hypo->type->cid
- PgfAbsCat* arg =
- gu_map_get(abscats, hypo->type->cid, PgfAbsCat*);
-
#ifdef PGF_JIT_DEBUG
gu_puts(" CALL ", out, err);
gu_string_write(hypo->type->cid, out, err);
@@ -219,14 +229,11 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
jit_prepare(2);
jit_pusharg_p(JIT_V2);
jit_pusharg_p(JIT_V1);
- if (arg != NULL) {
- jit_finish(arg->predicate);
- } else {
- PgfCallPatch patch;
- patch.cid = hypo->type->cid;
- patch.ref = jit_finish(jit_forward());
- gu_buf_push(state->patches, PgfCallPatch, patch);
- }
+
+ PgfCallPatch patch;
+ patch.cid = hypo->type->cid;
+ patch.ref = jit_finish(jit_forward());
+ gu_buf_push(rdr->jit_state->patches, PgfCallPatch, patch);
#ifdef PGF_JIT_DEBUG
gu_puts(" RET\n", out, err);
@@ -239,7 +246,7 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
jit_ret();
if (i+1 < n_hypos) {
- pgf_jit_make_space(state);
+ pgf_jit_make_space(rdr);
jit_patch_movi(ref,jit_get_label());
@@ -254,18 +261,17 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
}
} else {
if (i+1 < n_funs) {
- PgfAbsFun* absfun =
- gu_buf_get(functions, PgfAbsFun*, i+1);
+ next_absfun = pgf_jit_read_absfun(rdr, abstr); // i+1
#ifdef PGF_JIT_DEBUG
gu_puts(" TRY_CONSTANT ", out, err);
- gu_string_write(absfun->name, out, err);
+ gu_string_write(next_absfun->name, out, err);
gu_puts("\n", out, err);
#endif
// compile TRY_CONSTANT
jit_prepare(3);
- jit_movi_p(JIT_V0, absfun);
+ jit_movi_p(JIT_V0, next_absfun);
jit_pusharg_p(JIT_V0);
jit_pusharg_p(JIT_V2);
jit_pusharg_p(JIT_V1);
@@ -289,13 +295,10 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
// compile RET
jit_ret();
}
-
+
#ifdef PGF_JIT_DEBUG
if (i+1 < n_funs) {
- PgfAbsFun* absfun =
- gu_buf_get(functions, PgfAbsFun*, i+1);
-
- gu_string_write(absfun->name, out, err);
+ gu_string_write(next_absfun->name, out, err);
gu_puts(":\n", out, err);
}
#endif
@@ -307,18 +310,251 @@ pgf_jit_predicate(PgfJitState* state, PgfCIdMap* abscats,
}
void
-pgf_jit_done(PgfJitState* state, PgfAbstr* abstr)
+pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
+ PgfAbsFun* absfun)
{
- size_t n_patches = gu_buf_length(state->patches);
+#ifdef PGF_JIT_DEBUG
+ GuPool* tmp_pool = gu_new_pool();
+ GuOut* out = gu_file_out(stderr, tmp_pool);
+ GuExn* err = gu_exn(NULL, type, tmp_pool);
+
+ gu_string_write(absfun->name, out, err);
+ gu_puts(":\n", out, err);
+#endif
+
+ pgf_jit_make_space(rdr);
+
+ absfun->function = jit_get_ip().ptr;
+
+ jit_prolog(2);
+
+ int es_arg = jit_arg_p();
+ int closure_arg = jit_arg_p();
+
+ size_t n_instrs = pgf_read_len(rdr);
+ gu_return_on_exn(rdr->err, );
+
+ size_t curr_offset = 0;
+ size_t curr_label = 0;
+
+ for (size_t i = 0; i < n_instrs; i++) {
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "%04d ", curr_label++);
+#endif
+
+ uint8_t opcode = pgf_read_tag(rdr);
+ switch (opcode) {
+ case PGF_INSTR_EVAL: {
+ size_t index = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "EVAL %d\n", index);
+#endif
+
+ jit_getarg_p(JIT_V0, es_arg);
+ jit_ldxi_p(JIT_V0, JIT_V0, offsetof(PgfEvalState,stack));
+ jit_prepare(1);
+ jit_pusharg_p(JIT_V0);
+ jit_finish(gu_buf_length);
+ jit_subi_i(JIT_V2, JIT_RET, index+1);
+ jit_lshi_i(JIT_V2, JIT_V2, 2);
+ jit_prepare(1);
+ jit_pusharg_p(JIT_V0);
+ jit_finish(gu_buf_data);
+ jit_ldxr_p(JIT_V0, JIT_RET, JIT_V2);
+ jit_prepare(2);
+ jit_pusharg_p(JIT_V0);
+ jit_getarg_p(JIT_V2, es_arg);
+ jit_pusharg_p(JIT_V2);
+ jit_ldr_p(JIT_V0, JIT_V0);
+ jit_callr(JIT_V0);
+ break;
+ }
+ case PGF_INSTR_CASE: {
+ PgfCId id = pgf_read_cid(rdr, rdr->opool);
+ int offset = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "CASE %s %04d\n", id, curr_label+offset);
+#endif
+ break;
+ }
+ case PGF_INSTR_CASE_INT: {
+ int n = pgf_read_int(rdr);
+ int offset = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "CASE_INT %d %04d\n", n, curr_label+offset);
+#endif
+ break;
+ }
+ case PGF_INSTR_CASE_STR: {
+ GuString s = pgf_read_string(rdr);
+ int offset = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "CASE_STR %s %04d\n", s, curr_label+offset);
+#endif
+ break;
+ }
+ case PGF_INSTR_CASE_FLT: {
+ double d = pgf_read_double(rdr);
+ int offset = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "CASE_FLT %f %04d\n", d, curr_label+offset);
+#endif
+ break;
+ }
+ case PGF_INSTR_ALLOC: {
+ size_t size = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "ALLOC %d\n", size);
+#endif
+ jit_prepare(2);
+ jit_movi_ui(JIT_V0, size*sizeof(void*));
+ jit_pusharg_ui(JIT_V0);
+ jit_getarg_p(JIT_V0, es_arg);
+ jit_ldxi_p(JIT_V0, JIT_V0, offsetof(PgfEvalState,pool));
+ jit_pusharg_p(JIT_V0);
+ jit_finish(gu_malloc);
+ jit_retval_p(JIT_V1);
+
+ curr_offset = 0;
+ break;
+ }
+ case PGF_INSTR_PUT_CONSTR: {
+ PgfCId id = pgf_read_cid(rdr, rdr->tmp_pool);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "PUT_CONSTR %s\n", id);
+#endif
+
+ jit_movi_p(JIT_V0, pgf_evaluate_value);
+ jit_stxi_p(curr_offset*sizeof(void*), JIT_V1, JIT_V0);
+ curr_offset++;
+
+ PgfCallPatch patch;
+ patch.cid = id;
+ patch.ref = jit_movi_p(JIT_V0, jit_forward());
+ jit_stxi_p(curr_offset*sizeof(void*), JIT_V1, JIT_V0);
+ curr_offset++;
+
+ gu_buf_push(rdr->jit_state->patches, PgfCallPatch, patch);
+ break;
+ }
+ case PGF_INSTR_PUT_CLOSURE: {
+ size_t addr = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "PUT_CLOSURE %d\n", addr);
+#endif
+ break;
+ }
+ case PGF_INSTR_PUT_INT: {
+ size_t n = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "PUT_INT %d\n", n);
+#endif
+ break;
+ }
+ case PGF_INSTR_PUT_STR: {
+ size_t addr = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "PUT_STR %d\n", addr);
+#endif
+ break;
+ }
+ case PGF_INSTR_PUT_FLT: {
+ size_t addr = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "PUT_FLT %d\n", addr);
+#endif
+
+ break;
+ }
+ case PGF_INSTR_SET_VALUE: {
+ size_t offset = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "SET_VALUE %d\n", offset);
+#endif
+ jit_addi_p(JIT_V0, JIT_V1, offset*sizeof(void*));
+ jit_stxi_p(curr_offset*sizeof(void*), JIT_V1, JIT_V0);
+ curr_offset++;
+ break;
+ }
+ case PGF_INSTR_SET_VARIABLE: {
+ size_t index = pgf_read_int(rdr);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "SET_VARIABLE %d\n", index);
+#endif
+
+ jit_getarg_p(JIT_V0, es_arg);
+ jit_ldxi_p(JIT_V0, JIT_V0, offsetof(PgfEvalState,stack));
+ jit_prepare(1);
+ jit_pusharg_p(JIT_V0);
+ jit_finish(gu_buf_length);
+ jit_subi_i(JIT_V2, JIT_RET, index+1);
+ jit_lshi_i(JIT_V2, JIT_V2, 2);
+ jit_prepare(1);
+ jit_pusharg_p(JIT_V0);
+ jit_finish(gu_buf_data);
+ jit_ldxr_p(JIT_V0, JIT_RET, JIT_V2);
+ jit_stxi_p(curr_offset*sizeof(void*), JIT_V1, JIT_V0);
+ break;
+ }
+ case PGF_INSTR_TAIL_CALL: {
+ PgfCId id = pgf_read_cid(rdr, rdr->tmp_pool);
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "TAIL_CALL %s\n", id);
+#endif
+ break;
+ }
+ case PGF_INSTR_FAIL:
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "FAIL\n");
+#endif
+ break;
+ case PGF_INSTR_RET: {
+ size_t count = pgf_read_int(rdr);
+
+#ifdef PGF_JIT_DEBUG
+ gu_printf(out, err, "RET %d\n", count);
+#endif
+
+ jit_prepare(2);
+ jit_movi_ui(JIT_V0, count);
+ jit_pusharg_p(JIT_V0);
+ jit_getarg_p(JIT_V0, es_arg);
+ jit_ldxi_p(JIT_V0, JIT_V0, offsetof(PgfEvalState,stack));
+ jit_pusharg_p(JIT_V0);
+ jit_finish(gu_buf_trim_n);
+
+ jit_movr_p(JIT_RET, JIT_V1);
+ jit_ret();
+ break;
+ }
+ default:
+ gu_impossible();
+ }
+ }
+}
+
+void
+pgf_jit_done(PgfReader* rdr, PgfAbstr* abstr)
+{
+ size_t n_patches = gu_buf_length(rdr->jit_state->patches);
for (size_t i = 0; i < n_patches; i++) {
PgfCallPatch* patch =
- gu_buf_index(state->patches, PgfCallPatch, i);
+ gu_buf_index(rdr->jit_state->patches, PgfCallPatch, i);
+
PgfAbsCat* arg =
gu_map_get(abstr->cats, patch->cid, PgfAbsCat*);
- gu_assert(arg != NULL);
-
- jit_patch_calli(patch->ref,(jit_insn*) arg->predicate);
+ if (arg != NULL)
+ jit_patch_calli(patch->ref,(jit_insn*) arg->predicate);
+ else {
+ PgfAbsFun* con =
+ gu_map_get(abstr->funs, patch->cid, PgfAbsFun*);
+ if (con != NULL)
+ jit_patch_movi(patch->ref,con);
+ else {
+ gu_impossible();
+ }
+ }
}
- jit_flush_code(state->buf, jit_get_ip().ptr);
+ jit_flush_code(rdr->jit_state->buf, jit_get_ip().ptr);
}