From 10a50dd20abe8542d6ed6487d2c46d964af59c75 Mon Sep 17 00:00:00 2001 From: eunhhu Date: Mon, 5 Oct 2026 22:53:09 +0100 Subject: Batch executor stage 1 (024): a count's loop whose block has batch forms (lane forms, locals set before read in every round, ifs, numbers set in items) runs, in the executor, up to 1024 rounds at a time: values uniform, affine or lanes (numbers, or whole numbers in four bytes), branches as masks, cells read by affine rows as strided columns, sets kept to the batch's end and made only when no round reads an earlier round's; a fault, a form it lacks or such a read gives the rounds back to the executor one by one, work counted as written. Planned at load (PURE_BATCH=0: none); the executor of a module without such loops is the same code (run aligned to 64: as many instructions and cycles), with one its own copy. knapsack with PURE_JIT=0: 1,056 to 13.7 ms. module_tier compares batches with the executor alone and makes loops of rounds apart; BATCH_SOURCE: widened columns, -0, a fault mid-batch, rounds reading the last's sets --- core/module-run.h | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) (limited to 'core/module-run.h') diff --git a/core/module-run.h b/core/module-run.h index fac77a4..1e48072 100644 --- a/core/module-run.h +++ b/core/module-run.h @@ -4,9 +4,59 @@ * (module-jit.c): their frame, and the steps the compiled code calls. Not a * public interface. */ #include "module.h" +#include +#include -/* An item's or a key's op->plan: its cell a text; a FIND joined to the ITEM_GET after it. */ -enum { PLAN_TEXT = 1, PLAN_JOINED = 2, PLAN_ROW = 4 }; +/* Read from a message's bytes (little-endian). */ +static inline uint32_t read32(const unsigned char *p) { + return (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24; +} + +static inline double read_double(const unsigned char *p) { + uint64_t bits = read32(p) | (uint64_t)read32(p + 4) << 32; + double value; + memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline double minimum(double a, double b) { return a < b || (a == b && signbit(a)) ? a : b; } +static inline double maximum(double a, double b) { return a > b || (a == b && !signbit(a)) ? a : b; } + +/* a op b as run computes it; false where run faults. */ +static inline bool number_op(uint8_t op, double a, double b, double *out) { + double value; + switch (op) { + case PURE_OP_ADD: value = a + b; break; + case PURE_OP_SUB: value = a - b; break; + case PURE_OP_MUL: value = a * b; break; + case PURE_OP_DIV: + if (b == 0) return false; + value = a / b; + break; + case PURE_OP_LT: value = a < b; break; + case PURE_OP_LE: value = a <= b; break; + case PURE_OP_GT: value = a > b; break; + case PURE_OP_GE: value = a >= b; break; + case PURE_OP_EQ: value = a == b; break; + case PURE_OP_NE: value = a != b; break; + case PURE_OP_AND: value = a != 0 && b != 0; break; + case PURE_OP_OR: value = a != 0 || b != 0; break; + case PURE_OP_MIN: value = minimum(a, b); break; + case PURE_OP_MOD: + if (b == 0) return false; + value = fmod(a, b); + if (value != 0 && (value < 0) != (b < 0)) value += b; + else if (value == 0) value = copysign(0.0, b); + break; + default: value = maximum(a, b); break; + } + *out = value; + return isfinite(value); +} + +/* An item's or a key's op->plan: its cell a text; a FIND joined to the ITEM_GET after it; a FIND whose row an ITEM_SET + * takes; a LOOP whose block a batch may run (module-batch.c). */ +enum { PLAN_TEXT = 1, PLAN_JOINED = 2, PLAN_ROW = 4, PLAN_BATCH = 8 }; /* An item instruction's argument: its list and its field. */ static inline uint32_t list_of(uint32_t arg) { return arg & 0xFFFF; } @@ -20,7 +70,8 @@ typedef struct { uint32_t list; size_t at, end; bool removed; } Walk; /* A loop that runs in its block's run (LOOP, EACH): its block and where * the code around it ends, the arena as it began, a walk's walk and the * event's walk and row around it, a count's values (low + k of count) and - * slot. */ + * slot, and the round from which batches may run its rounds (UINT64_MAX: + * none), how many failed and which way their lanes run. */ typedef struct { uint32_t start, end, outer; size_t mark; @@ -29,6 +80,9 @@ typedef struct { size_t row; uint64_t count, k; PureValue low, *slot; + uint64_t resume; + unsigned failures; + bool reverse; /* a batch's lanes run its rounds backwards */ } Loop; typedef struct { PureApp *app; @@ -83,8 +137,9 @@ static inline uint32_t after(const PureOp *op, uint32_t pc) { * instruction but a branch or a loop's (how; the next is after()); a walk or * a loop opened at pc (STEP_NEXT: its block next, STEP_SKIP: none, past its * block); BREAK; a loop's block ran once (STEP_NEXT: again, STEP_DONE: the - * loop ended). */ -enum { STEP_SKIP = 4, STEP_DONE = 5 }; + * loop ended). STEP_BATCH: step leaves a LOOP planned PLAN_BATCH to its + * caller (module.c). */ +enum { STEP_SKIP = 4, STEP_DONE = 5, STEP_BATCH = 6 }; int pure_run_step(Frame *, uint32_t pc); int pure_run_each(Frame *, uint32_t pc); int pure_run_loop(Frame *, uint32_t pc); @@ -101,6 +156,13 @@ int pure_run_item(Frame *, uint32_t pc); * stopped. */ int pure_run_rest(Frame *, uint32_t pc); +/* Loops a batch of rounds at a time (module-batch.c, docs/design/024): the + * innermost loop's rounds from loop->k (set up and counted; its LOOP + * planned PLAN_BATCH) run as one batch: how many (0: none ran, its block + * runs round by round next, at least until round loop->resume), the frame + * left as the last of them leaves it, their work counted. */ +unsigned pure_batch_run(Frame *, Loop *); + /* Where a list keeps what compiled code reads of it (module-list.c owns the * layout and says where): its item count, its key set (the words, how many, * whether they are bits), its form (pure_list_form), its arrays and the rows -- cgit v1.2.3