From 5db97c60b953205e68d273b9b56424d346fa750d Mon Sep 17 00:00:00 2001 From: eunhhu Date: Mon, 19 Oct 2026 11:51:58 +0100 Subject: 045: 029's principle 1 broken on UAX #14 before any emitter, the tools and the numbers: (a) the executor runs 549.9 instructions a code point (the budget's 1,774 counts blocks as written), moves 205.5, constants 76.7 and reads of the same list, version, field and place in an event 16.4, so merging leaves 251.3: 2.19x, the bar 4x (ops-count.patch); (b) the executor's own steps stitched on constant instructions, a function a basic block (stitch.c, native-hook.patch), answers checked: 40,703 to 28,601 machine instructions a point, 15,566 to 11,850 cycles: 1.31x, the bar 3x (cost.c); Vega's C 220 and 82; where it goes: dispatch 22 machine instructions an instruction of 74, an empty handler 1,583 a point, the lists built 22,651 more, the Text record 2,951, decide 12,988 (events.c, variants); a stored list's read 331, a block fn's call 1,375, an arithmetic step 248 in the executor and 35 in batches (unit.c, units) --- .../experiments/045-proof-compiler/ops-count.patch | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 research/experiments/045-proof-compiler/ops-count.patch (limited to 'research/experiments/045-proof-compiler/ops-count.patch') diff --git a/research/experiments/045-proof-compiler/ops-count.patch b/research/experiments/045-proof-compiler/ops-count.patch new file mode 100644 index 0000000..616ad09 --- /dev/null +++ b/research/experiments/045-proof-compiler/ops-count.patch @@ -0,0 +1,62 @@ +diff --git a/core/module.c b/core/module.c +index 4b20e25..2205f77 100644 +--- a/core/module.c ++++ b/core/module.c +@@ -3902,7 +3902,57 @@ static __attribute__((noinline, cold)) int open_batches(Frame *frame, uint32_t p + #define STOPPED(why) do { frame->status = (why); return STEP_RETURN; } while (0) + + /* The instruction op at pc; *next the one to run after it. */ ++/* Research only (029's breaking experiment): the instructions the executor runs, by opcode. */ ++#include ++static uint64_t research_ops[256], research_same[256]; ++static const char *const research_names[] = {"CONST", "LOAD", "ADD", "SUB", "MUL", "DIV", "NEG", "LT", "LE", "GT", "GE", "EQ", "NE", "AND", "OR", "NOT", "MIN", "MAX", "CLAMP", "STORE", "JZ", "JMP", "FIELD", "LEN", "REPLY", "REQUIRE", "TEXT_CONST", "TEXT_LOAD", "NUM_TEXT", "CONCAT", "CHARS", "LINES", "TEXT_BYTES", "ANCHOR_LOAD", "ANCHOR_START", "ANCHOR_END", "ANCHOR_MOVE", "ANCHOR_STORE", "TEXT_INSERT", "TEXT_REMOVE", "TEXT_LINE", "TEXT_SET", "TEXT_FROM", "BYTES_FROM", "ANCHOR_COUNT", "LIST_COUNT", "LIST_APPEND", "LIST_INSERT", "LIST_REMOVE", "ITEM_GET", "ITEM_SET", "ROW", "PICK", "SLIDE", "FOLD", "TEXT_COMPARE", "LIST_FIND", "LIST_HAS", "NOW", "FLOOR", "MOD", "SEND", "OUTER_ROW", "EACH", "LOCAL_LOAD", "LOCAL_STORE", "I64_ADD", "I64_SUB", "I64_MUL", "I64_DIV", "I64_MOD", "I64_NEG", "I64_COMPARE", "I64_MIN", "I64_MAX", "I64_FROM", "NUM_FROM", "LOOP", "BREAK", "I64_BITS", "BYTE_AT", "BYTES_OF", "ANCHOR_AT", "BYTES_SLICE", "BYTE", "BYTES_LOAD", "BYTES_STORE", "LIST_VALUE", "LIST_BIND", "APPEND_IN", "NUM_PARSE", "CALL", "RETURN", "CHAR_AT", "CHAR", "FLOORDIV", "CUR_LOAD", "CUR_START", "CUR_END", "CUR_MOVE", "CUR_STORE", "CUR_COUNT", "CUR_AT", "INDEX_LOAD", "INDEX_STORE", "INDEX_MOVE", "INDEX_FIRST", "INDEX_LAST", "INDEX_NUM", "INDEX_AT", "KEPT_GET", "KEPT_SET", "KEPT_APPEND", "KEPT_INSERT", "KEPT_APPEND_IN"}; ++static void research_reads(const Frame *frame, const PureOp *op); ++static void research_dump(void) { ++ const char *out = getenv("PURE_OPS_OUT"); ++ FILE *f = out ? fopen(out, "w") : stderr; ++ for (unsigned i = 0; i < 256; ++i) ++ if (research_ops[i]) fprintf(f, "%s %llu %llu\n", i < sizeof(research_names) / sizeof(*research_names) ? research_names[i] : "?", ++ (unsigned long long)research_ops[i], (unsigned long long)research_same[i]); ++ if (out) fclose(f); ++} ++/* Reads the proof makes the same: the same list (its address and version: a change makes another), field and place ++ * read again within an event (the event's work starts again at 0). Counted by opcode. */ ++static uint64_t research_last_work, research_keys[1 << 16]; ++static uint32_t research_key_count; ++static void research_reads(const Frame *frame, const PureOp *op) { ++ if (frame->app->work < research_last_work) memset(research_keys, 0, sizeof(research_keys)), research_key_count = 0; ++ research_last_work = frame->app->work; ++ uint64_t list = 0, version = 0, place = 0, id = 0; ++ switch (op->op) { ++ case PURE_OP_ITEM_GET: case PURE_OP_INDEX_AT: case PURE_OP_LIST_COUNT: { ++ uint32_t state = op->op == PURE_OP_ITEM_GET ? (op->arg & 0xFFFF) : op->arg; ++ if (state >= frame->app->laid && state < PURE_LIST_HEARD) return; ++ const PureList *l = frame->app->lists[state]; ++ if (!l) return; ++ pure_list_stamp(l, &id, &version); ++ list = (uint64_t)(uintptr_t)l; ++ if (op->op != PURE_OP_LIST_COUNT) memcpy(&place, &frame->stack[frame->sp - 1], sizeof(place)); ++ break; ++ } ++ case PURE_OP_LIST_BIND: { ++ list = 0x51ull << 56 | op->arg; ++ memcpy(&place, &frame->stack[frame->sp - 1], sizeof(place)); ++ version = 0; ++ break; ++ } ++ default: return; ++ } ++ uint64_t key = ((list * 0x9E3779B97F4A7C15ull) ^ (version * 0xC2B2AE3D27D4EB4Full) ^ (place * 0x165667B19E3779F9ull) ^ ++ ((uint64_t)op->op << 32 | op->arg)) | 1; ++ for (uint32_t i = (uint32_t)(key >> 40) & 0xFFFF, k = 0; k < 1 << 16; ++k, i = (i + 1) & 0xFFFF) { ++ if (research_keys[i] == key) { ++research_same[op->op]; return; } ++ if (!research_keys[i]) { if (research_key_count < (1 << 15)) research_keys[i] = key, ++research_key_count; return; } ++ } ++} ++__attribute__((constructor)) static void research_start(void) { atexit(research_dump); } + static inline __attribute__((always_inline)) int step(Frame *frame, const PureOp *op, uint32_t pc, uint32_t *next, bool batches) { ++ ++research_ops[op->op]; ++ research_reads(frame, op); + const PureModule *m = frame->m; + PureValue *values = frame->values; + Event *ev = frame->ev; -- cgit v1.2.3