diff options
| -rw-r--r-- | core/module-jit.c | 26 | ||||
| -rw-r--r-- | core/module.c | 21 |
2 files changed, 36 insertions, 11 deletions
diff --git a/core/module-jit.c b/core/module-jit.c index 8e50eb0..49c763f 100644 --- a/core/module-jit.c +++ b/core/module-jit.c @@ -730,8 +730,18 @@ static bool compile_block(const PureModule *m, PureBlock block, unsigned end_hei typedef struct { PureBlock block; unsigned leaves; size_t entry; } Made; -/* A block to make, leaving leaves values on the stack. */ -static bool want(PureBlock block, unsigned leaves, Made **made, size_t *count, size_t *room) { +/* Whether a block has a loop: compiled code pays where blocks repeat; a + * short block runs once (a view's cell, a fold's item, most handlers) as + * fast in the executor, without the code's entry and its calls of step. */ +static bool loops_in(const PureModule *m, PureBlock block) { + for (uint32_t pc = block.start; pc < block.start + block.length; ++pc) + if (m->code[pc].op == PURE_OP_EACH || m->code[pc].op == PURE_OP_LOOP) return true; + return false; +} + +/* A block to make (one with a loop), leaving leaves values on the stack. */ +static bool want(const PureModule *m, PureBlock block, unsigned leaves, Made **made, size_t *count, size_t *room) { + if (!loops_in(m, block)) return true; for (size_t i = 0; i < *count; ++i) if ((*made)[i].block.start == block.start && (*made)[i].block.length == block.length) return true; if (!grow_array((void **)made, room, *count + 1, sizeof(**made))) return false; @@ -746,17 +756,21 @@ struct PureJit *pure_jit_make(const PureModule *m) { size_t count = 0, room = 0; bool ok = true; /* The handlers' and the views' code, then the folds' blocks in what is made (they run as blocks of their own). */ - for (uint32_t h = 0; ok && h < m->handlers; ++h) ok = want(m->handler[h].code, 0, &made, &count, &room); + for (uint32_t h = 0; ok && h < m->handlers; ++h) ok = want(m, m->handler[h].code, 0, &made, &count, &room); for (uint32_t v = 0; ok && v < m->views; ++v) - if (m->view_code[v].length) ok = want(m->view_code[v], 1, &made, &count, &room); + if (m->view_code[v].length) ok = want(m, m->view_code[v], 1, &made, &count, &room); for (size_t i = 0; ok && i < count; ++i) for (uint32_t pc = made[i].block.start; ok && pc < made[i].block.start + made[i].block.length; ++pc) { const PureOp *op = &m->code[pc]; unsigned how = op->arg & PURE_FOLD_KIND; /* count and first leave a bool; the others a value and a bool */ if (op->op == PURE_OP_FOLD) - ok = want((PureBlock){pc + 1, op->arg >> 16}, how == PURE_FOLD_COUNT || how == PURE_FOLD_FIRST ? 1 : 2, &made, &count, - &room); + ok = want(m, (PureBlock){pc + 1, op->arg >> 16}, how == PURE_FOLD_COUNT || how == PURE_FOLD_FIRST ? 1 : 2, &made, + &count, &room); } + if (ok && !count) { /* nothing worth it: run() then looks for no code at all */ + free(made); + return NULL; + } Emit e = {0}; for (size_t i = 0; ok && i < count; ++i) ok = compile_block(m, made[i].block, made[i].leaves, &e, &made[i].entry); ok = ok && resolve(&e); diff --git a/core/module.c b/core/module.c index c486d45..8771cab 100644 --- a/core/module.c +++ b/core/module.c @@ -2294,7 +2294,7 @@ static size_t group_slot(uint64_t bits, size_t capacity) { } /* key's group, added when absent (with add); NULL when absent, or without room. */ -static Group *group_of(struct PurePass *pass, double key, unsigned how, bool add) { +static inline __attribute__((always_inline)) Group *group_of(struct PurePass *pass, double key, unsigned how, bool add) { key = key == 0 ? 0 : key; if (pass->capacity) { for (size_t at = group_slot(order_bits(key), pass->capacity);; at = (at + 1) & (pass->capacity - 1)) { @@ -3071,13 +3071,24 @@ int pure_run_iterate(Frame *frame) { return how != STEP_NEXT ? how : next != UINT32_MAX ? STEP_NEXT : STEP_DONE; } +/* A frame for block, its fields set one by one: a block runs often (a + * fold's item, a view's cell), and filling the whole frame each time (the + * compiled code's run among it) costs more than the block. */ +static inline __attribute__((always_inline)) void open_frame(Frame *frame, const PureModule *m, PureValue *values, PureBlock block, + Event *ev, Slot *stack, Loop *loops) { + frame->m = m, frame->values = values, frame->ev = ev, frame->app = ev->app, frame->arena = ev->arena; + frame->stack = stack, frame->sp = 0, frame->loops = loops, frame->depth = 0; + frame->end = block.start + block.length; +} + /* A block run by its compiled code. */ static __attribute__((noinline)) PureResult run_compiled(PureCompiled code, const PureModule *m, PureValue *values, PureBlock block, Event *ev, Slot *result) { Slot stack[PURE_MODULE_STACK]; Loop loops[PURE_MODULE_NESTING]; - Frame frame = {.m = m, .values = values, .ev = ev, .app = ev->app, .arena = ev->arena, .stack = stack, - .end = block.start + block.length, .loops = loops}; + Frame frame; + open_frame(&frame, m, values, block, ev, stack, loops); + frame.run.list = NULL; /* no run kept yet */ return finish(&frame, code(&frame), result); } @@ -3086,8 +3097,8 @@ static PureResult run(const PureModule *m, PureValue *values, PureBlock block, E if (code) return run_compiled(code, m, values, block, ev, result); Slot stack[PURE_MODULE_STACK]; Loop loops[PURE_MODULE_NESTING]; - Frame frame = {.m = m, .values = values, .ev = ev, .app = ev->app, .arena = ev->arena, .stack = stack, - .end = block.start + block.length, .loops = loops}; + Frame frame; + open_frame(&frame, m, values, block, ev, stack, loops); int how = STEP_NEXT; for (uint32_t pc = block.start;;) { if (pc >= frame.end) { /* the block ran; or a loop's ran once: again, or the loop ends (its end may be its outer's) */ |
