Skip to main content

RISCV_RUNTIME_C

Constant RISCV_RUNTIME_C 

Source
pub const RISCV_RUNTIME_C: &str = "\n/* LC_GC_COLLECTOR_BEGIN */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#if defined(__GLIBC__) || defined(__APPLE__)\n#define LC_GC_COLLECTS 1\n#include <setjmp.h>\n#include <sys/mman.h>\n#if defined(__SANITIZE_ADDRESS__)\n#define LC_GC_CHECKED_HEAP 1\n#elif defined(__has_feature)\n#if __has_feature(address_sanitizer)\n#define LC_GC_CHECKED_HEAP 1\n#endif\n#endif\n#if defined(__APPLE__)\n#include <pthread.h>\n#include <mach-o/dyld.h>\n#include <mach-o/getsect.h>\n#endif\n\n/* The collector: mark from the roots, sweep what was not reached. Two heaps share its marking and its policy:\n   - the paged heap (shipped builds): blocks of 64 KiB, each cut into slots of one size class, found from any\n     address through a two-level page map, so an allocation pops a free list and a sweep is one pass over a block\'s\n     mark bits; an object larger than the largest class is its own malloc\'d block behind a header, found through a\n     table of them sorted by address at each collection, and resized in place by the C library where it can be;\n   - the checked heap (builds with AddressSanitizer): every object is its own malloc\'d block, found through a table\n     sorted by address at each collection, so the sanitizer sees each object\'s bounds and LeakSanitizer each one\n     the sweep fails to free.\n   A slot holds a 16-byte pad, then the object, then one byte: a word anywhere in it \u{2014} the object\'s start, inside\n   it, one past its end, or a little before its start \u{2014} holds it. */\n\ntypedef struct { uintptr_t lo, hi; } lc_gc_range;\n\nstatic lc_gc_range *lc_gc_roots; static size_t lc_gc_roots_n, lc_gc_roots_cap;\nstatic lc_gc_range lc_gc_left[64]; static int lc_gc_left_n;\nstatic uintptr_t lc_gc_stack_hi;\nstatic size_t lc_gc_since, lc_gc_trigger = (size_t)8 << 20;\nstatic int lc_gc_started, lc_gc_stress, lc_gc_collecting;\n/* The heap\'s ledger, in the bytes each object takes in its heap (a small object\'s slot; a large object\'s header and\n   payload; in the checked heap, every object\'s header and payload): what is held now, the most ever held at once\n   (taken at each allocation, before the collection it may trigger), what was held after the last collection, the\n   collections run, and what was allocated and freed in all. Deterministic but for conservative retention: a block a\n   non-pointer word happens to point into stays held. */\nstatic size_t lc_gc_live, lc_gc_high, lc_gc_after, lc_gc_collections, lc_gc_allocated, lc_gc_freed;\n/* The marking stack: the objects reached and not yet scanned, as ranges. */\nstatic lc_gc_range *lc_gc_pending; static size_t lc_gc_pending_n, lc_gc_pending_cap;\n/* The objects that hold memory outside the heap (a linked runtime\'s), each with what gives that memory back: a\n   collection calls it for each one it did not reach, before the sweep frees the object, and the teardown for each\n   one left. The runtime that holds the memory may count its bytes, which the next collection\'s trigger counts as\n   the heap\'s own, and add to the heap report. */\ntypedef struct { void *object; void (*release)(void *); } lc_gc_hold;\nstatic lc_gc_hold *lc_gc_holds; static size_t lc_gc_holds_n, lc_gc_holds_cap;\nstatic size_t (*lc_gc_outside)(void);\nstatic void (*lc_gc_outside_report)(FILE *);\n\n__attribute__((noreturn)) static void lc_gc_exhausted(void) {\n    fflush(stdout);\n    fputs(\"memory allocation failed\\n\", stderr);\n    exit(1);\n}\n\n/* The C library\'s allocator, for the collector\'s own tables and pages, which it never scans as objects. */\nstatic void *lc_gc_table(void *p, size_t n) {\n    void *q = realloc(p, n);\n    if (!q) lc_gc_exhausted();\n    return q;\n}\n\nstatic void lc_gc_push(uintptr_t lo, uintptr_t hi) {\n    if (lc_gc_pending_n == lc_gc_pending_cap) {\n        lc_gc_pending_cap = lc_gc_pending_cap ? lc_gc_pending_cap * 2 : 1024;\n        lc_gc_pending = (lc_gc_range *)lc_gc_table(lc_gc_pending, lc_gc_pending_cap * sizeof *lc_gc_pending);\n    }\n    lc_gc_pending[lc_gc_pending_n++] = (lc_gc_range){lo, hi};\n}\n\n#define LC_GC_PAD 16\n\n#ifndef LC_GC_CHECKED_HEAP\n/* ---- The paged heap ---- */\n#define LC_GC_BLOCK ((uintptr_t)1 << 16)\n#define LC_GC_CLASSES 21\n#define LC_GC_SMALL 2048\n/* The slot sizes: pad + object + one byte, rounded up. */\nstatic const uint32_t lc_gc_class_size[LC_GC_CLASSES] = {\n    32, 48, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 640, 768, 1024, 1280, 1536, 2048};\n/* A block of slots of one class. */\ntypedef struct lc_gc_blk {\n    uintptr_t start;\n    uint32_t size;          /* the slot size */\n    uint32_t nslots;\n    uint8_t atomic;\n    uint8_t cls;\n    uint64_t *marks;        /* one bit per slot */\n    uint64_t *allocated;    /* only allocated slots may enter tracing */\n    struct lc_gc_blk *next; /* the blocks of one class and kind */\n} lc_gc_blk;\n/* A large object\'s header: its size, its place in the table, whether it is atomic, its mark. */\ntypedef struct { size_t size; uint32_t index; uint8_t atomic; uint8_t marked; } lc_gc_hdr;\nstatic lc_gc_blk *lc_gc_classes[2][LC_GC_CLASSES];\nstatic lc_gc_hdr **lc_gc_large; static size_t lc_gc_large_n, lc_gc_large_cap;\nstatic uint8_t lc_gc_class_of_16[(LC_GC_SMALL / 16) + 1];\n/* Blocks come from the system LC_GC_CHUNK at a time, each mapping cut to a block boundary, so nothing pads a block to\n   its alignment and the address space a heap takes is its blocks\'; a block a sweep empties waits among the spares for\n   reuse, and goes back to the system past them. */\n#define LC_GC_CHUNK 64\n/* The collector\'s own state that points into the heap or indexes it: the free lists, the heap\'s bounds, the page\n   map (address bits 47..32, then 31..16, to the block that owns those 64 KiB), the chunk blocks are cut from and the\n   spare blocks. The globals scan skips it, or every free slot would hold the next one. */\nstatic struct {\n    void *free_list[2][LC_GC_CLASSES];\n    uintptr_t heap_lo, heap_hi, large_lo, large_hi;\n    uintptr_t chunk_next, chunk_end;\n    uintptr_t spare[LC_GC_CHUNK];\n    int spare_n;\n    lc_gc_blk **map[1 << 16];\n} lc_gc_own = {.heap_lo = UINTPTR_MAX};\n\n/* A block\'s memory: a spare, else the next block of the chunk, mapping a fresh chunk when that one is used up. */\nstatic uintptr_t lc_gc_block_take(void) {\n    if (lc_gc_own.spare_n) return lc_gc_own.spare[--lc_gc_own.spare_n];\n    if (lc_gc_own.chunk_next == lc_gc_own.chunk_end) {\n        size_t want = (size_t)LC_GC_BLOCK * LC_GC_CHUNK, span = want + LC_GC_BLOCK;\n        char *m = (char *)mmap(0, span, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);\n        if (m == MAP_FAILED) lc_gc_exhausted();\n        uintptr_t lo = ((uintptr_t)m + LC_GC_BLOCK - 1) & ~(LC_GC_BLOCK - 1), hi = lo + want;\n        if (lo > (uintptr_t)m) munmap(m, lo - (uintptr_t)m);\n        if ((uintptr_t)m + span > hi) munmap((void *)hi, (uintptr_t)m + span - hi);\n        lc_gc_own.chunk_next = lo;\n        lc_gc_own.chunk_end = hi;\n    }\n    uintptr_t b = lc_gc_own.chunk_next;\n    lc_gc_own.chunk_next += LC_GC_BLOCK;\n    return b;\n}\n\n/* A block\'s memory no block holds any more. */\nstatic void lc_gc_block_give(uintptr_t b) {\n    if (lc_gc_own.spare_n < LC_GC_CHUNK) lc_gc_own.spare[lc_gc_own.spare_n++] = b;\n    else munmap((void *)b, LC_GC_BLOCK);\n}\n\nstatic void lc_gc_heap_init(void) {\n    int c = 0;\n    for (size_t k = 0; k <= LC_GC_SMALL / 16; k++) {\n        while (lc_gc_class_size[c] < k * 16) c++;\n        lc_gc_class_of_16[k] = (uint8_t)c;\n    }\n}\n\nstatic void lc_gc_map_set(uintptr_t at, uintptr_t end, lc_gc_blk *b) {\n    for (uintptr_t a = at & ~(LC_GC_BLOCK - 1); a < end; a += LC_GC_BLOCK) {\n        size_t top = (a >> 32) & 0xFFFF;\n        if (!lc_gc_own.map[top]) {\n            lc_gc_own.map[top] = (lc_gc_blk **)calloc((size_t)1 << 16, sizeof(lc_gc_blk *));\n            if (!lc_gc_own.map[top]) lc_gc_exhausted();\n        }\n        lc_gc_own.map[top][(a >> 16) & 0xFFFF] = b;\n    }\n    if (at < lc_gc_own.heap_lo) lc_gc_own.heap_lo = at;\n    if (end > lc_gc_own.heap_hi) lc_gc_own.heap_hi = end;\n}\n\nstatic inline lc_gc_blk *lc_gc_owner(uintptr_t w) {\n    lc_gc_blk **second = lc_gc_own.map[(w >> 32) & 0xFFFF];\n    return second ? second[(w >> 16) & 0xFFFF] : 0;\n}\n\n/* A fresh block of class `c`, its slots on the free list. */\nstatic void lc_gc_new_block(int atomic, int c) {\n    lc_gc_blk *b = (lc_gc_blk *)calloc(1, sizeof *b);\n    if (!b) lc_gc_exhausted();\n    b->start = lc_gc_block_take();\n    b->size = lc_gc_class_size[c];\n    b->nslots = (uint32_t)(LC_GC_BLOCK / b->size);\n    b->atomic = (uint8_t)atomic;\n    b->cls = (uint8_t)c;\n    b->marks = (uint64_t *)calloc((b->nslots + 63) / 64, sizeof(uint64_t));\n    b->allocated = (uint64_t *)calloc((b->nslots + 63) / 64, sizeof(uint64_t));\n    if (!b->marks || !b->allocated) lc_gc_exhausted();\n    b->next = lc_gc_classes[atomic][c];\n    lc_gc_classes[atomic][c] = b;\n    lc_gc_map_set(b->start, b->start + LC_GC_BLOCK, b);\n    void *head = lc_gc_own.free_list[atomic][c];\n    for (uint32_t i = b->nslots; i-- > 0;) {\n        void *slot = (void *)(b->start + (uintptr_t)i * b->size);\n        *(void **)slot = head;\n        head = slot;\n    }\n    lc_gc_own.free_list[atomic][c] = head;\n}\n\n/* The bytes an object of `n` takes in the heap: its slot, or a large object\'s header and payload. */\nstatic inline size_t lc_gc_takes(size_t n) {\n    size_t need = n + LC_GC_PAD + 1;\n    return need <= LC_GC_SMALL ? lc_gc_class_size[lc_gc_class_of_16[(need + 15) / 16]] : sizeof(lc_gc_hdr) + n;\n}\n\nstatic void *lc_gc_heap_alloc(size_t n, int atomic) {\n    size_t need = n + LC_GC_PAD + 1;\n    if (need <= LC_GC_SMALL) {\n        int c = lc_gc_class_of_16[(need + 15) / 16];\n        void *slot = lc_gc_own.free_list[atomic][c];\n        if (!slot) {\n            lc_gc_new_block(atomic, c);\n            slot = lc_gc_own.free_list[atomic][c];\n        }\n        lc_gc_own.free_list[atomic][c] = *(void **)slot;\n        lc_gc_blk *b = lc_gc_owner((uintptr_t)slot);\n        uint32_t i = (uint32_t)(((uintptr_t)slot - b->start) / b->size);\n        b->allocated[i >> 6] |= (uint64_t)1 << (i & 63);\n        /* Unwritten pointer-bearing capacity must not retain a prior occupant. */\n        if (!atomic) memset((char *)slot + LC_GC_PAD, 0, b->size - LC_GC_PAD - 1);\n        lc_gc_live += lc_gc_class_size[c];\n        lc_gc_allocated += lc_gc_class_size[c];\n        return (char *)slot + LC_GC_PAD;\n    }\n    lc_gc_live += sizeof(lc_gc_hdr) + n;\n    lc_gc_allocated += sizeof(lc_gc_hdr) + n;\n    lc_gc_hdr *h = (lc_gc_hdr *)malloc(sizeof *h + n + 1);\n    if (!h) lc_gc_exhausted();\n    if (!atomic) memset(h + 1, 0, n);\n    h->size = n;\n    h->atomic = (uint8_t)atomic;\n    h->marked = 0;\n    if (lc_gc_large_n == (size_t)UINT32_MAX) lc_gc_exhausted();\n    if (lc_gc_large_n == lc_gc_large_cap) {\n        lc_gc_large_cap = lc_gc_large_cap ? lc_gc_large_cap * 2 : 256;\n        lc_gc_large = (lc_gc_hdr **)lc_gc_table(lc_gc_large, lc_gc_large_cap * sizeof *lc_gc_large);\n    }\n    h->index = (uint32_t)lc_gc_large_n;\n    lc_gc_large[lc_gc_large_n++] = h;\n    return h + 1;\n}\n\n/* Whether object `p` is a small one, in a block of slots. */\nstatic inline int lc_gc_is_small(void *p) { return lc_gc_owner((uintptr_t)p) != 0; }\n\n/* The bytes object `p` can hold. */\nstatic size_t lc_gc_capacity(void *p) {\n    lc_gc_blk *b = lc_gc_owner((uintptr_t)p);\n    return b ? b->size - LC_GC_PAD - 1 : ((lc_gc_hdr *)p - 1)->size;\n}\n\nstatic void lc_gc_unmap(uintptr_t at, uintptr_t end) {\n    for (uintptr_t a = at & ~(LC_GC_BLOCK - 1); a < end; a += LC_GC_BLOCK) lc_gc_own.map[(a >> 32) & 0xFFFF][(a >> 16) & 0xFFFF] = 0;\n}\n\nstatic void lc_gc_heap_free(void *p) {\n    lc_gc_blk *b = lc_gc_owner((uintptr_t)p);\n    if (!b) {\n        lc_gc_hdr *h = (lc_gc_hdr *)p - 1;\n        size_t i = h->index;\n        lc_gc_live -= sizeof *h + h->size;\n        lc_gc_freed += sizeof *h + h->size;\n        lc_gc_large[i] = lc_gc_large[--lc_gc_large_n];\n        lc_gc_large[i]->index = (uint32_t)i;\n        free(h);\n        return;\n    }\n    lc_gc_live -= b->size;\n    lc_gc_freed += b->size;\n    void *slot = (char *)p - LC_GC_PAD;\n    uint32_t i = (uint32_t)(((uintptr_t)slot - b->start) / b->size);\n    b->allocated[i >> 6] &= ~((uint64_t)1 << (i & 63));\n    *(void **)slot = lc_gc_own.free_list[b->atomic][b->cls];\n    lc_gc_own.free_list[b->atomic][b->cls] = slot;\n}\n\n/* A large object resized by the C library, in place where it can be. */\nstatic void *lc_gc_large_resize(void *p, size_t n) {\n    lc_gc_hdr *h = (lc_gc_hdr *)p - 1;\n    size_t i = h->index, was = h->size;\n    lc_gc_hdr *g = (lc_gc_hdr *)realloc(h, sizeof *g + n + 1);\n    if (!g) lc_gc_exhausted();\n    if (!g->atomic && n > was) memset((char *)(g + 1) + was, 0, n - was);\n    g->size = n;\n    lc_gc_large[i] = g;\n    if (n > was) { lc_gc_live += n - was; lc_gc_allocated += n - was; }\n    else { lc_gc_live -= was - n; lc_gc_freed += was - n; }\n    return g + 1;\n}\n\nstatic int lc_gc_by_address(const void *a, const void *b) {\n    uintptr_t x = (uintptr_t)*(lc_gc_hdr *const *)a, y = (uintptr_t)*(lc_gc_hdr *const *)b;\n    return x < y ? -1 : x > y;\n}\n\nstatic void lc_gc_prepare(void) {\n    for (int a = 0; a < 2; a++)\n        for (int c = 0; c < LC_GC_CLASSES; c++)\n            for (lc_gc_blk *b = lc_gc_classes[a][c]; b; b = b->next) memset(b->marks, 0, ((b->nslots + 63) / 64) * sizeof(uint64_t));\n    qsort(lc_gc_large, lc_gc_large_n, sizeof *lc_gc_large, lc_gc_by_address);\n    for (size_t i = 0; i < lc_gc_large_n; i++) {\n        lc_gc_large[i]->index = (uint32_t)i;\n        lc_gc_large[i]->marked = 0;\n    }\n    lc_gc_own.large_lo = lc_gc_large_n ? (uintptr_t)lc_gc_large[0] : 0;\n    lc_gc_own.large_hi = lc_gc_large_n ? (uintptr_t)(lc_gc_large[lc_gc_large_n - 1] + 1) + lc_gc_large[lc_gc_large_n - 1]->size : 0;\n}\n\n/* A word into a large object: mark it and queue it to be scanned. */\nstatic void lc_gc_consider_large(uintptr_t w) {\n    size_t lo = 0, hi = lc_gc_large_n;\n    while (hi - lo > 1) {\n        size_t mid = lo + (hi - lo) / 2;\n        if ((uintptr_t)lc_gc_large[mid] <= w) lo = mid; else hi = mid;\n    }\n    lc_gc_hdr *h = lc_gc_large[lo];\n    if (w < (uintptr_t)h || w > (uintptr_t)(h + 1) + h->size || h->marked) return;\n    h->marked = 1;\n    if (!h->atomic) lc_gc_push((uintptr_t)(h + 1), (uintptr_t)(h + 1) + h->size);\n}\n\n/* The word `w`, if it points into an object not yet marked: mark it and queue it to be scanned. */\nstatic inline void lc_gc_consider(uintptr_t w) {\n    w &= ~(uintptr_t)1;\n    if (lc_gc_large_n && w >= lc_gc_own.large_lo && w <= lc_gc_own.large_hi && !lc_gc_owner(w)) {\n        lc_gc_consider_large(w);\n        return;\n    }\n    if (w < lc_gc_own.heap_lo || w >= lc_gc_own.heap_hi) return;\n    lc_gc_blk *b = lc_gc_owner(w);\n    if (!b) return;\n    uint32_t i = (uint32_t)((w - b->start) / b->size);\n    if (i >= b->nslots) return;\n    uint64_t bit = (uint64_t)1 << (i & 63);\n    if (!(b->allocated[i >> 6] & bit) || (b->marks[i >> 6] & bit)) return;\n    b->marks[i >> 6] |= bit;\n    if (!b->atomic) {\n        uintptr_t s = b->start + (uintptr_t)i * b->size;\n        lc_gc_push(s + LC_GC_PAD, s + b->size - 1);\n    }\n}\n\n/* Whether the marking reached object `p`. */\nstatic int lc_gc_reached(void *p) {\n    lc_gc_blk *b = lc_gc_owner((uintptr_t)p);\n    if (!b) return ((lc_gc_hdr *)p - 1)->marked;\n    uint32_t i = (uint32_t)(((uintptr_t)p - b->start) / b->size);\n    return (int)((b->marks[i >> 6] >> (i & 63)) & 1);\n}\n\n/* Rebuild every free list from the unmarked slots; free every unmarked large object and every block left empty.\n   Answers the bytes left live and adds the bytes freed to `*freed`. */\nstatic size_t lc_gc_sweep(size_t *freed) {\n    size_t live = 0;\n    for (int a = 0; a < 2; a++) {\n        for (int c = 0; c < LC_GC_CLASSES; c++) {\n            void *head = 0;\n            lc_gc_blk **at = &lc_gc_classes[a][c];\n            while (*at) {\n                lc_gc_blk *b = *at;\n                uint32_t used = 0;\n                for (uint32_t w = 0; w < (b->nslots + 63) / 64; w++) used += (uint32_t)__builtin_popcountll(b->marks[w]);\n                if (used == 0) {\n                    *at = b->next;\n                    lc_gc_unmap(b->start, b->start + LC_GC_BLOCK);\n                    lc_gc_block_give(b->start);\n                    free(b->marks);\n                    free(b->allocated);\n                    free(b);\n                    *freed += LC_GC_BLOCK;\n                    continue;\n                }\n                for (uint32_t i = b->nslots; i-- > 0;) {\n                    if (!(b->marks[i >> 6] & ((uint64_t)1 << (i & 63)))) {\n                        void *slot = (void *)(b->start + (uintptr_t)i * b->size);\n                        *(void **)slot = head;\n                        head = slot;\n                    }\n                }\n                memcpy(b->allocated, b->marks, ((b->nslots + 63) / 64) * sizeof(uint64_t));\n                live += (size_t)used * b->size;\n                *freed += (size_t)(b->nslots - used) * b->size;\n                at = &b->next;\n            }\n            lc_gc_own.free_list[a][c] = head;\n        }\n    }\n    size_t kept = 0;\n    for (size_t i = 0; i < lc_gc_large_n; i++) {\n        lc_gc_hdr *h = lc_gc_large[i];\n        if (h->marked) {\n            h->index = (uint32_t)kept;\n            lc_gc_large[kept++] = h;\n            live += h->size + sizeof *h;\n        } else {\n            *freed += h->size + sizeof *h;\n            free(h);\n        }\n    }\n    lc_gc_large_n = kept;\n    return live;\n}\n\nstatic void lc_gc_heap_teardown(void) {\n    for (int a = 0; a < 2; a++) {\n        for (int c = 0; c < LC_GC_CLASSES; c++) {\n            lc_gc_blk *b = lc_gc_classes[a][c];\n            while (b) {\n                lc_gc_blk *next = b->next;\n                munmap((void *)b->start, LC_GC_BLOCK);\n                free(b->marks);\n                free(b->allocated);\n                free(b);\n                b = next;\n            }\n            lc_gc_classes[a][c] = 0;\n            lc_gc_own.free_list[a][c] = 0;\n        }\n    }\n    for (int k = 0; k < lc_gc_own.spare_n; k++) munmap((void *)lc_gc_own.spare[k], LC_GC_BLOCK);\n    lc_gc_own.spare_n = 0;\n    if (lc_gc_own.chunk_next < lc_gc_own.chunk_end)\n        munmap((void *)lc_gc_own.chunk_next, lc_gc_own.chunk_end - lc_gc_own.chunk_next);\n    lc_gc_own.chunk_next = lc_gc_own.chunk_end = 0;\n    for (size_t i = 0; i < lc_gc_large_n; i++) free(lc_gc_large[i]);\n    free(lc_gc_large);\n    lc_gc_large = 0;\n    lc_gc_large_n = lc_gc_large_cap = 0;\n    for (size_t top = 0; top < ((size_t)1 << 16); top++) {\n        free(lc_gc_own.map[top]);\n        lc_gc_own.map[top] = 0;\n    }\n}\n#else\n/* ---- The checked heap ---- */\n/* An object\'s block: its header (the object\'s size, its place in the table, whether it is atomic), then the\n   object, then one byte. */\ntypedef struct { size_t size; uint32_t index; uint32_t atomic; } lc_gc_hdr;\nstatic lc_gc_hdr **lc_gc_blocks; static size_t lc_gc_count, lc_gc_cap;\nstatic unsigned char *lc_gc_marks; static size_t lc_gc_marks_cap;\nstatic lc_gc_hdr **lc_gc_sorting; static size_t lc_gc_sorting_cap;\n/* The collector\'s own state that points into the heap or sorts it: the heap\'s bounds and the sort\'s counts. The\n   globals scan skips it. */\nstatic struct { uintptr_t heap_lo, heap_hi; size_t counts[1 << 16]; } lc_gc_own;\n\nstatic void lc_gc_heap_init(void) {}\n\nstatic inline size_t lc_gc_takes(size_t n) { return sizeof(lc_gc_hdr) + n; }\n\nstatic void *lc_gc_heap_alloc(size_t n, int atomic) {\n    if (lc_gc_count == (size_t)UINT32_MAX) lc_gc_exhausted();\n    lc_gc_hdr *h = (lc_gc_hdr *)malloc(sizeof *h + n + 1);\n    if (!h) lc_gc_exhausted();\n    if (!atomic) memset(h + 1, 0, n);\n    h->size = n;\n    h->atomic = (uint32_t)atomic;\n    lc_gc_live += sizeof *h + n;\n    lc_gc_allocated += sizeof *h + n;\n    if (lc_gc_count == lc_gc_cap) {\n        lc_gc_cap = lc_gc_cap ? lc_gc_cap * 2 : 1024;\n        lc_gc_blocks = (lc_gc_hdr **)lc_gc_table(lc_gc_blocks, lc_gc_cap * sizeof *lc_gc_blocks);\n    }\n    h->index = (uint32_t)lc_gc_count;\n    lc_gc_blocks[lc_gc_count++] = h;\n    return h + 1;\n}\n\nstatic size_t lc_gc_capacity(void *p) { return ((lc_gc_hdr *)p - 1)->size; }\n\nstatic void lc_gc_heap_free(void *p) {\n    lc_gc_hdr *h = (lc_gc_hdr *)p - 1;\n    size_t i = h->index;\n    lc_gc_live -= sizeof *h + h->size;\n    lc_gc_freed += sizeof *h + h->size;\n    lc_gc_blocks[i] = lc_gc_blocks[--lc_gc_count];\n    lc_gc_blocks[i]->index = (uint32_t)i;\n    free(h);\n}\n\n/* The table in address order: a radix sort over the addresses\' low 48 bits, sixteen at a time. */\nstatic void lc_gc_prepare(void) {\n    if (lc_gc_sorting_cap < lc_gc_count) {\n        lc_gc_sorting_cap = lc_gc_cap;\n        lc_gc_sorting = (lc_gc_hdr **)lc_gc_table(lc_gc_sorting, lc_gc_sorting_cap * sizeof *lc_gc_sorting);\n    }\n    size_t *counts = lc_gc_own.counts;\n    lc_gc_hdr **from = lc_gc_blocks, **to = lc_gc_sorting;\n    for (int shift = 0; shift < 48; shift += 16) {\n        memset(counts, 0, sizeof lc_gc_own.counts);\n        for (size_t i = 0; i < lc_gc_count; i++) counts[((uintptr_t)from[i] >> shift) & 0xFFFF]++;\n        size_t at = 0;\n        for (size_t d = 0; d < (1 << 16); d++) { size_t c = counts[d]; counts[d] = at; at += c; }\n        for (size_t i = 0; i < lc_gc_count; i++) to[counts[((uintptr_t)from[i] >> shift) & 0xFFFF]++] = from[i];\n        lc_gc_hdr **t = from; from = to; to = t;\n    }\n    if (from != lc_gc_blocks) memcpy(lc_gc_blocks, from, lc_gc_count * sizeof *lc_gc_blocks);\n    for (size_t i = 0; i < lc_gc_count; i++) lc_gc_blocks[i]->index = (uint32_t)i;\n    lc_gc_own.heap_lo = lc_gc_count ? (uintptr_t)lc_gc_blocks[0] : 0;\n    lc_gc_own.heap_hi = lc_gc_count ? (uintptr_t)(lc_gc_blocks[lc_gc_count - 1] + 1) + lc_gc_blocks[lc_gc_count - 1]->size : 0;\n    if (lc_gc_marks_cap < lc_gc_count) {\n        lc_gc_marks_cap = lc_gc_count * 2;\n        lc_gc_marks = (unsigned char *)lc_gc_table(lc_gc_marks, lc_gc_marks_cap);\n    }\n    if (lc_gc_count) memset(lc_gc_marks, 0, lc_gc_count);\n}\n\nstatic inline void lc_gc_consider(uintptr_t w) {\n    w &= ~(uintptr_t)1;\n    if (!lc_gc_count || w < lc_gc_own.heap_lo || w > lc_gc_own.heap_hi) return;\n    size_t lo = 0, hi = lc_gc_count;\n    while (hi - lo > 1) {\n        size_t mid = lo + (hi - lo) / 2;\n        if ((uintptr_t)lc_gc_blocks[mid] <= w) lo = mid; else hi = mid;\n    }\n    lc_gc_hdr *h = lc_gc_blocks[lo];\n    if (w < (uintptr_t)h || w > (uintptr_t)(h + 1) + h->size || lc_gc_marks[lo]) return;\n    lc_gc_marks[lo] = 1;\n    if (!h->atomic) lc_gc_push((uintptr_t)(h + 1), (uintptr_t)(h + 1) + h->size);\n}\n\nstatic int lc_gc_reached(void *p) { return lc_gc_marks[((lc_gc_hdr *)p - 1)->index]; }\n\nstatic size_t lc_gc_sweep(size_t *freed) {\n    size_t kept = 0, live = 0;\n    for (size_t i = 0; i < lc_gc_count; i++) {\n        lc_gc_hdr *h = lc_gc_blocks[i];\n        if (lc_gc_marks[i]) {\n            h->index = (uint32_t)kept;\n            lc_gc_blocks[kept++] = h;\n            live += h->size + sizeof *h;\n        } else {\n            *freed += h->size + sizeof *h;\n            free(h);\n        }\n    }\n    lc_gc_count = kept;\n    return live;\n}\n\nstatic void lc_gc_heap_teardown(void) {\n    for (size_t i = 0; i < lc_gc_count; i++) free(lc_gc_blocks[i]);\n    free(lc_gc_blocks);\n    free(lc_gc_marks);\n    free(lc_gc_sorting);\n    lc_gc_blocks = 0; lc_gc_marks = 0; lc_gc_sorting = 0;\n    lc_gc_count = lc_gc_cap = lc_gc_marks_cap = lc_gc_sorting_cap = 0;\n}\n#endif\n\nstatic void lc_gc_teardown(void);\n\n/* The base of the stack the program starts on. */\nstatic uintptr_t lc_gc_main_stack_base(void) {\n#if defined(__APPLE__)\n    return (uintptr_t)pthread_get_stackaddr_np(pthread_self());\n#elif defined(__GLIBC__)\n    extern void *__libc_stack_end;\n    return (uintptr_t)__libc_stack_end;\n#endif\n}\n\n/* The collector starts at the program\'s first allocation, its marking stack reserved then: a collection, which runs\n   when memory is short, allocates nothing until marking outgrows it. */\nstatic void lc_gc_start(void) {\n    lc_gc_started = 1;\n    const char *s = getenv(\"LOGOS_GC_STRESS\");\n    lc_gc_stress = s && s[0] == \'1\' && s[1] == 0;\n    lc_gc_stack_hi = lc_gc_main_stack_base();\n    lc_gc_heap_init();\n    lc_gc_pending_cap = 1024;\n    lc_gc_pending = (lc_gc_range *)lc_gc_table(lc_gc_pending, lc_gc_pending_cap * sizeof *lc_gc_pending);\n    atexit(lc_gc_teardown);\n}\n\n/* Every aligned word of [lo, hi). It reads the stack\'s and the globals\' padding too, which address sanitizing\n   would report, so it is not instrumented. */\n__attribute__((no_sanitize_address, noinline)) static void lc_gc_scan(uintptr_t lo, uintptr_t hi) {\n    for (uintptr_t a = (lo + 7) & ~(uintptr_t)7; a + 8 <= hi; a += 8) lc_gc_consider(*(const uintptr_t *)a);\n}\n\n/* The program\'s data and bss segments: its globals and this runtime\'s statics. */\nstatic void lc_gc_scan_globals(void) {\n#if defined(__APPLE__)\n    const struct mach_header_64 *mh = (const struct mach_header_64 *)_dyld_get_image_header(0);\n    const char *segments[] = {\"__DATA\", \"__DATA_DIRTY\"};\n    for (int k = 0; k < 2; k++) {\n        unsigned long size = 0;\n        uint8_t *at = getsegmentdata(mh, segments[k], &size);\n        if (!at) continue;\n        uintptr_t lo = (uintptr_t)at, hi = lo + size, own = (uintptr_t)&lc_gc_own, own_end = (uintptr_t)(&lc_gc_own + 1);\n        if (own >= lo && own_end <= hi) {\n            lc_gc_scan(lo, own);\n            lc_gc_scan(own_end, hi);\n        } else {\n            lc_gc_scan(lo, hi);\n        }\n    }\n#else\n    extern char __data_start[], _end[];\n    lc_gc_scan((uintptr_t)__data_start, (uintptr_t)&lc_gc_own);\n    lc_gc_scan((uintptr_t)(&lc_gc_own + 1), (uintptr_t)_end);\n#endif\n}\n\n/* The running stack, from below this frame to its base: the caller spills its registers into it first. */\n__attribute__((noinline)) static void lc_gc_scan_stack(void) {\n    volatile uintptr_t top = 0;\n    lc_gc_scan((uintptr_t)&top, lc_gc_stack_hi);\n}\n\nstatic void lc_gc_collect(void) {\n    if (lc_gc_collecting) return;\n    lc_gc_collecting = 1;\n    lc_gc_prepare();\n    lc_gc_pending_n = 0;\n    /* The registers, spilled into this frame, which the stack scan below covers. */\n    jmp_buf regs;\n    setjmp(regs);\n    lc_gc_scan_stack();\n    for (int k = 0; k < lc_gc_left_n; k++) lc_gc_scan(lc_gc_left[k].lo, lc_gc_left[k].hi);\n    for (size_t k = 0; k < lc_gc_roots_n; k++) lc_gc_scan(lc_gc_roots[k].lo, lc_gc_roots[k].hi);\n    lc_gc_scan_globals();\n    while (lc_gc_pending_n) {\n        lc_gc_range r = lc_gc_pending[--lc_gc_pending_n];\n        lc_gc_scan(r.lo, r.hi);\n    }\n    if (lc_gc_holds_n) {\n        size_t kept = 0;\n        for (size_t k = 0; k < lc_gc_holds_n; k++) {\n            lc_gc_hold h = lc_gc_holds[k];\n            if (lc_gc_reached(h.object)) lc_gc_holds[kept++] = h;\n            else h.release(h.object);\n        }\n        lc_gc_holds_n = kept;\n    }\n    size_t before = lc_gc_live, unused = 0, live = lc_gc_sweep(&unused);\n    size_t freed = before > live ? before - live : 0;\n    lc_gc_freed += freed;\n    lc_gc_live = live;\n    lc_gc_after = live;\n    lc_gc_collections++;\n    lc_gc_since = 0;\n    /* The next collection waits for twice the bytes held (the heap\'s live bytes and those its objects hold outside\n       it), four times when this one found little garbage. */\n    size_t held = live + (lc_gc_outside ? lc_gc_outside() : 0);\n    size_t next = freed * 4 < live + freed ? held * 4 : held * 2;\n    lc_gc_trigger = next > ((size_t)8 << 20) ? next : ((size_t)8 << 20);\n    lc_gc_collecting = 0;\n}\n\nstatic void lc_gc_teardown(void) {\n    const char *report = getenv(\"LOGOS_HEAP_REPORT\");\n    if (report && report[0]) {\n        fprintf(stderr, \"logos heap: live=%zu high=%zu collections=%zu allocated=%zu freed=%zu\",\n                lc_gc_collections ? lc_gc_after : lc_gc_live, lc_gc_high, lc_gc_collections, lc_gc_allocated, lc_gc_freed);\n        if (lc_gc_outside_report) lc_gc_outside_report(stderr);\n        fputc(\'\\n\', stderr);\n    }\n    for (size_t k = 0; k < lc_gc_holds_n; k++) lc_gc_holds[k].release(lc_gc_holds[k].object);\n    lc_gc_heap_teardown();\n    free(lc_gc_pending);\n    free(lc_gc_roots);\n    free(lc_gc_holds);\n    lc_gc_pending = 0; lc_gc_roots = 0; lc_gc_holds = 0;\n    lc_gc_pending_n = lc_gc_pending_cap = lc_gc_roots_n = lc_gc_roots_cap = lc_gc_holds_n = lc_gc_holds_cap = 0;\n}\n\n/* Before allocating `n` bytes: collect when due. */\nstatic inline void lc_gc_due(size_t n) {\n    if (__builtin_expect(!lc_gc_started, 0)) lc_gc_start();\n    lc_gc_since += n;\n    if (__builtin_expect(lc_gc_stress || lc_gc_since >= lc_gc_trigger, 0)) lc_gc_collect();\n}\n\n/* Both heap layouts reserve a header and a trailing byte. Check before\n   size-class arithmetic, ledger updates, collection, or libc allocation. */\nstatic inline void lc_gc_check_size(size_t n) {\n    if (n > SIZE_MAX - sizeof(lc_gc_hdr) - LC_GC_PAD - 1) lc_gc_exhausted();\n}\n\nstatic inline void *lc_gc_block(size_t n, int atomic) {\n    lc_gc_check_size(n);\n    if (__builtin_expect(!lc_gc_started, 0)) lc_gc_start();\n    size_t takes = lc_gc_takes(n);\n    if (lc_gc_live + takes > lc_gc_high) lc_gc_high = lc_gc_live + takes;\n    lc_gc_due(takes);\n    return lc_gc_heap_alloc(n, atomic);\n}\n\n__attribute__((unused, malloc)) static void *lc_gc_alloc(size_t n) { return lc_gc_block(n, 0); }\n__attribute__((unused, malloc)) static void *lc_gc_alloc_atomic(size_t n) { return lc_gc_block(n, 1); }\n\n__attribute__((unused, malloc)) static void *lc_gc_calloc(size_t count, size_t n) {\n    if (n && count > (size_t)-1 / n) lc_gc_exhausted();\n    void *p = lc_gc_alloc(count * n);\n    memset(p, 0, count * n);\n    return p;\n}\n\n__attribute__((unused, malloc)) static void *lc_gc_calloc_atomic(size_t count, size_t n) {\n    if (n && count > (size_t)-1 / n) lc_gc_exhausted();\n    void *p = lc_gc_alloc_atomic(count * n);\n    memset(p, 0, count * n);\n    return p;\n}\n\n__attribute__((unused)) static void lc_gc_free(void *p) {\n    if (p) lc_gc_heap_free(p);\n}\n\n/* A resize keeps a small object in its slot when it fits and lets the C library resize a large one in place where\n   it can; otherwise the object moves into a new one of the same kind. It counts only the bytes it adds. */\nstatic void *lc_gc_resize(void *p, size_t n, int atomic) {\n    lc_gc_check_size(n);\n    if (!p) return lc_gc_block(n, atomic);\n    size_t have = lc_gc_capacity(p);\n#ifndef LC_GC_CHECKED_HEAP\n    if (lc_gc_is_small(p)) {\n        if (n <= have) return p;\n    } else if (n + LC_GC_PAD + 1 > LC_GC_SMALL) {\n        lc_gc_due(n > have ? n - have : 0);\n        return lc_gc_large_resize(p, n);\n    }\n#endif\n    void *q = lc_gc_block(n, atomic);\n    memcpy(q, p, have < n ? have : n);\n    lc_gc_heap_free(p);\n    return q;\n}\n\n__attribute__((unused)) static void *lc_gc_realloc(void *p, size_t n) { return lc_gc_resize(p, n, 0); }\n__attribute__((unused)) static void *lc_gc_realloc_atomic(void *p, size_t n) { return lc_gc_resize(p, n, 1); }\n\n__attribute__((unused)) static void lc_gc_add_root(const void *lo, const void *hi) {\n    if (lc_gc_roots_n == lc_gc_roots_cap) {\n        lc_gc_roots_cap = lc_gc_roots_cap ? lc_gc_roots_cap * 2 : 16;\n        lc_gc_roots = (lc_gc_range *)lc_gc_table(lc_gc_roots, lc_gc_roots_cap * sizeof *lc_gc_roots);\n    }\n    lc_gc_roots[lc_gc_roots_n++] = (lc_gc_range){(uintptr_t)lo, (uintptr_t)hi};\n}\n\n__attribute__((unused)) static void lc_gc_remove_root(const void *lo) {\n    for (size_t k = 0; k < lc_gc_roots_n; k++) {\n        if (lc_gc_roots[k].lo == (uintptr_t)lo) {\n            lc_gc_roots[k] = lc_gc_roots[--lc_gc_roots_n];\n            return;\n        }\n    }\n}\n\n__attribute__((unused)) static void lc_gc_on_release(void *object, void (*release)(void *)) {\n    if (lc_gc_holds_n == lc_gc_holds_cap) {\n        lc_gc_holds_cap = lc_gc_holds_cap ? lc_gc_holds_cap * 2 : 256;\n        lc_gc_holds = (lc_gc_hold *)lc_gc_table(lc_gc_holds, lc_gc_holds_cap * sizeof *lc_gc_holds);\n    }\n    lc_gc_holds[lc_gc_holds_n++] = (lc_gc_hold){object, release};\n}\n\n__attribute__((unused)) static void lc_gc_count_outside(size_t (*bytes)(void), void (*report)(FILE *)) {\n    lc_gc_outside = bytes;\n    lc_gc_outside_report = report;\n}\n\n__attribute__((unused)) static void lc_gc_note_outside(size_t grown) { lc_gc_due(grown); }\n\n/* A scheduler moving onto the stack [lo, hi): the stack it leaves stays a root from its current top to its base. */\n__attribute__((unused, noinline)) static void lc_gc_stack_enter(const void *lo, const void *hi) {\n    if (!lc_gc_started) lc_gc_start();\n    volatile uintptr_t top = 0;\n    if (lc_gc_left_n == 64) lc_gc_exhausted();\n    lc_gc_left[lc_gc_left_n++] = (lc_gc_range){(uintptr_t)&top, lc_gc_stack_hi};\n    (void)lo;\n    lc_gc_stack_hi = (uintptr_t)hi;\n}\n\n__attribute__((unused)) static void lc_gc_stack_leave(void) {\n    lc_gc_range r = lc_gc_left[--lc_gc_left_n];\n    lc_gc_stack_hi = r.hi;\n}\n\n/* Worker steps are serialized by the scheduler mutex. The scheduler\'s original\n   stack stays registered until every worker joins; only the running worker\'s\n   stack is scanned as the current stack. */\n__attribute__((unused)) static void lc_gc_scheduler_stack_enter(const void *top) {\n    if (!lc_gc_started) lc_gc_start();\n    lc_gc_add_root(top, (const void *)lc_gc_stack_hi);\n}\n__attribute__((unused)) static uintptr_t lc_gc_worker_stack_enter(const void *top) {\n    uintptr_t saved = lc_gc_stack_hi;\n    lc_gc_stack_hi = (uintptr_t)top + sizeof(uintptr_t);\n    return saved;\n}\n__attribute__((unused)) static void lc_gc_worker_stack_leave(uintptr_t saved) {\n    lc_gc_stack_hi = saved;\n}\n\n#endif\n/* LC_GC_COLLECTOR_END */\n/* LC_GC_BEGIN \u{2014} the one allocator. Every block the program and this runtime allocate comes from it, and nothing else\n   calls the C library\'s allocator:\n     void *lc_gc_alloc(size_t n);                     malloc\'s contract\n     void *lc_gc_calloc(size_t count, size_t n);      zeroed\n     void *lc_gc_realloc(void *p, size_t n);          p == NULL allocates\n     void *lc_gc_alloc_atomic(size_t n);              a block that will never hold a pointer (text, bytes,\n     void *lc_gc_calloc_atomic(size_t count, size_t n);  digits, floats, flags, indices): never scanned,\n     void *lc_gc_realloc_atomic(void *p, size_t n);      and atomic across every resize\n     void  lc_gc_free(void *p);                       releases a block known dead now; NULL does nothing\n     char *lc_gc_strdup(const char *s);\n     char *lc_gc_strndup(const char *s, size_t n);\n     void  lc_gc_add_root(const void *lo, const void *hi);   [lo, hi) is scanned while registered\n     void  lc_gc_remove_root(const void *lo);\n     void  lc_gc_on_release(void *p, void (*release)(void *));   p holds memory outside the heap: release(p)\n                                                     gives it back once p is unreached, or at exit\n     void  lc_gc_count_outside(size_t (*bytes)(void), void (*report)(FILE *));   that memory\'s size, and what\n                                                     the heap report adds for it\n     void  lc_gc_note_outside(size_t grown);         that memory grew by `grown` bytes\n     void  lc_gc_stack_enter(const void *lo, const void *hi); a scheduler moves onto the stack [lo, hi)\n     void  lc_gc_stack_leave(void);                           and back onto the stack it left\n\n   A program built with LC_GC_COLLECTS also reclaims every block it can no longer reach, so its memory is bounded by\n   what it holds, and frees the rest at exit. The collector marks from its roots and sweeps what it did not reach:\n   - the roots: the running stack from its current top to its base (the registers spilled into it first), every\n     stack a scheduler has left (lc_gc_stack_enter / lc_gc_stack_leave), every range registered with\n     lc_gc_add_root, and the program\'s whole data and bss segments (its globals and this runtime\'s statics);\n   - every reached block is scanned word by word, so a block is held by any word that points into it: at its\n     start, inside it, one past its end, or into its header just before it, and with the low bit set (an exact\n     integer\'s tagged word `p | 1` points at its box);\n   - it runs once the bytes allocated since the last collection, and those its objects came to hold outside it,\n     pass the larger of 8 MiB and the bytes then held, and before every allocation when LOGOS_GC_STRESS=1 is in the\n     environment at the first allocation;\n   - at exit, after every handler registered later, it gives back what every object still holds outside the heap,\n     then frees every block, then its own tables.\n   The collector is C_GC_COLLECTOR, emitted ahead of this runtime; without it (LC_GC_COLLECTS undefined: another\n   generator, a device target, a platform whose segments it cannot find) the calls are the C library\'s. */\n#ifndef LC_GC_COLLECTS\n__attribute__((unused)) static inline void *lc_gc_alloc(size_t n) { return malloc(n); }\n__attribute__((unused)) static inline void *lc_gc_alloc_atomic(size_t n) { return malloc(n); }\n__attribute__((unused)) static inline void *lc_gc_calloc(size_t count, size_t n) { return calloc(count, n); }\n__attribute__((unused)) static inline void *lc_gc_calloc_atomic(size_t count, size_t n) { return calloc(count, n); }\n__attribute__((unused)) static inline void *lc_gc_realloc(void *p, size_t n) { return realloc(p, n); }\n__attribute__((unused)) static inline void *lc_gc_realloc_atomic(void *p, size_t n) { return realloc(p, n); }\n__attribute__((unused)) static inline void lc_gc_free(void *p) { free(p); }\n__attribute__((unused)) static inline void lc_gc_add_root(const void *lo, const void *hi) { (void)lo; (void)hi; }\n__attribute__((unused)) static inline void lc_gc_remove_root(const void *lo) { (void)lo; }\n__attribute__((unused)) static inline void lc_gc_on_release(void *p, void (*release)(void *)) { (void)p; (void)release; }\n__attribute__((unused)) static inline void lc_gc_count_outside(size_t (*bytes)(void), void (*report)(FILE *)) { (void)bytes; (void)report; }\n__attribute__((unused)) static inline void lc_gc_note_outside(size_t grown) { (void)grown; }\n__attribute__((unused)) static inline void lc_gc_stack_enter(const void *lo, const void *hi) { (void)lo; (void)hi; }\n__attribute__((unused)) static inline void lc_gc_stack_leave(void) {}\n__attribute__((unused)) static inline void lc_gc_scheduler_stack_enter(const void *top) { (void)top; }\n__attribute__((unused)) static inline uintptr_t lc_gc_worker_stack_enter(const void *top) { (void)top; return 0; }\n__attribute__((unused)) static inline void lc_gc_worker_stack_leave(uintptr_t saved) { (void)saved; }\n#endif\n__attribute__((unused)) static char *lc_gc_strdup(const char *s) {\n    size_t n = strlen(s);\n    char *t = (char *)lc_gc_alloc_atomic(n + 1);\n    memcpy(t, s, n + 1);\n    return t;\n}\n__attribute__((unused)) static char *lc_gc_strndup(const char *s, size_t n) {\n    size_t k = 0;\n    while (k < n && s[k]) k++;\n    char *t = (char *)lc_gc_alloc_atomic(k + 1);\n    memcpy(t, s, k);\n    t[k] = 0;\n    return t;\n}\n/* LC_GC_END */\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <errno.h>\n#include <stdint.h>\n#include <math.h>\n#include <time.h>\n#include <ucontext.h>\n#include <unistd.h>\n\n/* Nothing in a program unwinds: a failure prints its sentence and exits, and a task switches stacks by its\n   context. So the runtime\'s call-frame information goes to `.debug_frame`, which nothing reads at run time,\n   rather than `.eh_frame`, every entry of which a static binary\'s startup registers before `main`. */\n__asm__(\".cfi_sections .debug_frame\");\n\n/* A failure: the program stops with its reason alone on stderr, exit status 1 \u{2014} the report every tier\n   gives (`FailWith`, `Fail with \u{2026}`, a broken contract\'s reason, a runtime error) \u{2014} or, inside a task of\n   a concurrent program, the task stops and never returns here, and the run fails with its first\n   failure once every other task is quiescent (the scheduler installs `logos_fail_hook` for the run). */\nstatic void (*logos_fail_hook)(const char *) = 0;\n\n__attribute__((noreturn)) void logos_fatal(const char *reason) {\n    fflush(stdout);\n    if (logos_fail_hook) logos_fail_hook(reason);\n    fprintf(stderr, \"%s\\n\", reason);\n    exit(1);\n}\n\n__attribute__((noreturn)) static void logos_fatalf(const char *fmt, long long arg) {\n    char buf[256];\n    snprintf(buf, sizeof buf, fmt, arg);\n    logos_fatal(lc_gc_strdup(buf));\n}\n\n/* Rust\'s `char::is_whitespace`. */\nstatic int logos_is_space(unsigned cp) {\n    return (cp >= 0x09 && cp <= 0x0D) || cp == 0x20 || cp == 0x85 || cp == 0xA0 || cp == 0x1680\n        || (cp >= 0x2000 && cp <= 0x200A) || cp == 0x2028 || cp == 0x2029 || cp == 0x202F || cp == 0x205F\n        || cp == 0x3000;\n}\n\n/* The code point UTF-8 encodes at `s` into `cp`, answering its length in bytes. */\nstatic int logos_utf8_at(const unsigned char *s, unsigned *cp) {\n    if (s[0] < 0x80) { *cp = s[0]; return 1; }\n    if (s[0] < 0xE0) { *cp = ((s[0] & 0x1Fu) << 6) | (s[1] & 0x3Fu); return 2; }\n    if (s[0] < 0xF0) { *cp = ((s[0] & 0x0Fu) << 12) | ((s[1] & 0x3Fu) << 6) | (s[2] & 0x3Fu); return 3; }\n    *cp = ((s[0] & 0x07u) << 18) | ((s[1] & 0x3Fu) << 12) | ((s[2] & 0x3Fu) << 6) | (s[3] & 0x3Fu);\n    return 4;\n}\n\n/* `str::trim` \u{2014} a copy of `s` without its leading and trailing whitespace. */\nstatic char *logos_trim(const char *s) {\n    const unsigned char *b = (const unsigned char *)s, *e = b + strlen(s);\n    unsigned cp;\n    while (b < e) {\n        int n = logos_utf8_at(b, &cp);\n        if (!logos_is_space(cp)) break;\n        b += n;\n    }\n    while (e > b) {\n        const unsigned char *p = e - 1;\n        while (p > b && (*p & 0xC0) == 0x80) p--;\n        logos_utf8_at(p, &cp);\n        if (!logos_is_space(cp)) break;\n        e = p;\n    }\n    size_t n = (size_t)(e - b);\n    char *out = (char *)lc_gc_alloc_atomic(n + 1);\n    memcpy(out, b, n);\n    out[n] = \'\\0\';\n    return out;\n}\n\n/* The sentences an operation that fails stops the program with \u{2014} the VM\'s own, which the emitter takes from\n   the VM and emits beside the program, and which a helper reads only on its way to stopping:\n   `logos_index_refusal` is a format of the index (`%lld`), `logos_missing_key_refusal`, `logos_parse_int_refusal`\n   and `logos_parse_float_refusal` of a text (`%s`), `logos_random_bounds_refusal` of the two bounds\n   (`%1$lld`, `%2$lld`), `logos_utf8_invalid_refusal` of a sequence\'s length and start (`%1$d`, `%2$lld`) and\n   `logos_utf8_incomplete_refusal` of a start (`%lld`). */\nextern const char logos_index_refusal[], logos_missing_key_refusal[], logos_exact_division_refusal[],\n    logos_float_division_refusal[],\n    logos_negative_exponent_refusal[], logos_exponent_too_large_refusal[], logos_parse_int_refusal[],\n    logos_parse_float_refusal[], logos_random_bounds_refusal[], logos_utf8_invalid_refusal[],\n    logos_utf8_incomplete_refusal[], logos_await_without_listen_refusal[];\n\n/* The 0-based cell of index `i` among `len` that is not a 1-based one in range \u{2014} the rest of the VM\'s\n   `resolve_index`: `-i` counts from the back, and any other index stops the program. Every accessor tests the\n   1-based index in range itself, inline, and calls this out of line for everything else. */\n__attribute__((noinline, cold)) static long long logos_index_from_back(long long i, long long len) {\n    if (i <= -1 && (unsigned long long)0 - (unsigned long long)i <= (unsigned long long)len) return len + i;\n    logos_fatalf(logos_index_refusal, i);\n}\n\n/* The 0-based cell of 1-based index `i` among `len` (the VM\'s `resolve_index`). */\nstatic inline long long logos_resolve_index(long long i, long long len) {\n    if (__builtin_expect(i < 1 || i > len, 0)) return logos_index_from_back(i, len);\n    return i - 1;\n}\n\n/* Render an f64 into a fresh string EXACTLY like Rust\'s `{}` Display (see logos_show_f64). */\nchar *logos_fmt_f64(double x) {\n    if (isnan(x)) return lc_gc_strdup(\"NaN\");\n    if (isinf(x)) return lc_gc_strdup(x < 0 ? \"-inf\" : \"inf\");\n\n    /* Shortest significant-digit count whose scientific form round-trips. */\n    char sci[64];\n    int prec;\n    for (prec = 0; prec <= 17; prec++) {\n        snprintf(sci, sizeof sci, \"%.*e\", prec, x);\n        if (strtod(sci, NULL) == x) break;\n    }\n\n    /* Parse sci = [-]D[.FFF]e[+-]EE into a sign, a digit string, and a decimal exponent. */\n    const char *p = sci;\n    char sign = 0;\n    if (*p == \'-\') { sign = \'-\'; p++; }\n    char digits[40];\n    int nd = 0;\n    digits[nd++] = *p++;                 /* leading digit D */\n    if (*p == \'.\') { p++; while (*p != \'e\' && *p != \'E\') digits[nd++] = *p++; }\n    p++;                                  /* skip \'e\' */\n    int exp = atoi(p);                    /* decimal point sits after (exp+1) digits from the start */\n    int pointpos = exp + 1;\n\n    /* Reformat as fixed decimal (no exponent), matching Rust\'s Display. */\n    char *out = (char *)lc_gc_alloc_atomic(600);\n    int oi = 0;\n    if (sign) out[oi++] = \'-\';\n    if (pointpos <= 0) {\n        out[oi++] = \'0\';\n        out[oi++] = \'.\';\n        for (int i = 0; i < -pointpos; i++) out[oi++] = \'0\';\n        for (int i = 0; i < nd; i++) out[oi++] = digits[i];\n    } else if (pointpos >= nd) {\n        for (int i = 0; i < nd; i++) out[oi++] = digits[i];\n        for (int i = 0; i < pointpos - nd; i++) out[oi++] = \'0\';\n    } else {\n        for (int i = 0; i < nd; i++) {\n            if (i == pointpos) out[oi++] = \'.\';\n            out[oi++] = digits[i];\n        }\n    }\n    out[oi] = \'\\0\';\n    return out;\n}\n\nvoid logos_show_f64(double x) {\n    char *s = logos_fmt_f64(x);\n    printf(\"%s\\n\", s);\n    lc_gc_free(s);\n}\n\n/* ---- Text (heap char*) ---- */\n\n/* Stringify one slot value to a fresh string, by its static kind (0=Int, 1=Float, 2=Bool,\n * 3=Text) \u{2014} the AOT analog of `to_display_string`. `bits` is the raw 64-bit slot content (an i64, an\n * f64 bit pattern, 0/1, or a `char*`). */\n\n/* The sentences this section stops a program with, the VM\'s own, which the generator emits beside the program. */\nextern const char logos_says_big_exponent[], logos_says_bitand_fraction[], logos_says_bitand_refused[], logos_says_bitor_fraction[], logos_says_bitor_refused[], logos_says_bitxor_fraction[], logos_says_bitxor_refused[], logos_says_division_by_zero[], logos_says_exact_floor_division_by_zero[], logos_says_exponent_too_large[], logos_says_modulo_by_zero[], logos_says_modulo_int_rational[], logos_says_modulo_rational_int[], logos_says_modulo_rational_rational[], logos_says_negative_exponent[], logos_says_power_int_big[], logos_says_power_int_rational[], logos_says_power_rational_big[], logos_says_power_rational_rational[], logos_says_rational_division_by_zero[], logos_says_rational_exponent_too_large[], logos_says_shl_fraction[], logos_says_shl_refused[], logos_says_shr_fraction[], logos_says_shr_refused[];\n\n/* ========== Arbitrary-precision integer (LBig): sign-magnitude, little-endian base-1e9 limbs.\n   The substrate for LOGOS `Int` beyond int64 on the C backend \u{2014} byte-identical decimal I/O with the\n   interpreter\'s BigInt. Schoolbook add/sub/mul + exponentiation-by-squaring; O(n^2) mul is fine\n   (correctness over speed \u{2014} the C backend picks its fast path elsewhere). ========== */\n\n#define LBIG_BASE 1000000000u   /* 1e9 \u{2014} nine decimal digits per limb */\n\ntypedef struct { int sign; uint32_t *limb; size_t len; } LBig; /* sign in {-1,0,1}; zero => len==0 */\n\nstatic LBig lbig_make(size_t cap) {\n    LBig b; b.sign = 0; b.len = 0;\n    b.limb = (uint32_t *)lc_gc_calloc_atomic(cap ? cap : 1, sizeof(uint32_t));\n    return b;\n}\nstatic void lbig_free(LBig *b) { if (b->limb) lc_gc_free(b->limb); b->limb = NULL; b->len = 0; b->sign = 0; }\nstatic void lbig_trim(LBig *b) {\n    while (b->len > 0 && b->limb[b->len - 1] == 0) b->len--;\n    if (b->len == 0) b->sign = 0;\n}\nstatic LBig lbig_copy(const LBig *a) {\n    LBig r = lbig_make(a->len ? a->len : 1);\n    for (size_t i = 0; i < a->len; i++) r.limb[i] = a->limb[i];\n    r.len = a->len; r.sign = a->sign; return r;\n}\nstatic LBig lbig_from_u64(uint64_t v) {\n    LBig b = lbig_make(3);\n    size_t i = 0;\n    while (v > 0) { b.limb[i++] = (uint32_t)(v % LBIG_BASE); v /= LBIG_BASE; }\n    b.len = i; b.sign = (i > 0) ? 1 : 0;\n    return b;\n}\nstatic LBig lbig_from_i64(int64_t v) {\n    int neg = v < 0;\n    uint64_t u = neg ? (uint64_t)(-(v + 1)) + 1u : (uint64_t)v; /* safe for INT64_MIN */\n    LBig b = lbig_from_u64(u);\n    if (neg && b.len > 0) b.sign = -1;\n    return b;\n}\nstatic int lbig_cmp_mag(const LBig *a, const LBig *b) {\n    if (a->len != b->len) return a->len < b->len ? -1 : 1;\n    for (size_t i = a->len; i-- > 0; )\n        if (a->limb[i] != b->limb[i]) return a->limb[i] < b->limb[i] ? -1 : 1;\n    return 0;\n}\nstatic LBig lbig_add_mag(const LBig *a, const LBig *b) {\n    size_t n = (a->len > b->len ? a->len : b->len) + 1;\n    LBig r = lbig_make(n);\n    uint64_t carry = 0;\n    for (size_t i = 0; i < n; i++) {\n        uint64_t s = carry;\n        if (i < a->len) s += a->limb[i];\n        if (i < b->len) s += b->limb[i];\n        r.limb[i] = (uint32_t)(s % LBIG_BASE);\n        carry = s / LBIG_BASE;\n    }\n    r.len = n; r.sign = 1; lbig_trim(&r);\n    return r;\n}\nstatic LBig lbig_sub_mag(const LBig *a, const LBig *b) { /* requires |a| >= |b| */\n    LBig r = lbig_make(a->len);\n    int64_t borrow = 0;\n    for (size_t i = 0; i < a->len; i++) {\n        int64_t s = (int64_t)a->limb[i] - borrow - (i < b->len ? (int64_t)b->limb[i] : 0);\n        if (s < 0) { s += LBIG_BASE; borrow = 1; } else borrow = 0;\n        r.limb[i] = (uint32_t)s;\n    }\n    r.len = a->len; r.sign = 1; lbig_trim(&r);\n    return r;\n}\nstatic LBig lbig_add(const LBig *a, const LBig *b) {\n    if (a->sign == 0) return lbig_copy(b);\n    if (b->sign == 0) return lbig_copy(a);\n    if (a->sign == b->sign) { LBig r = lbig_add_mag(a, b); if (r.len) r.sign = a->sign; return r; }\n    int c = lbig_cmp_mag(a, b);\n    if (c == 0) return lbig_make(1);\n    if (c > 0) { LBig r = lbig_sub_mag(a, b); if (r.len) r.sign = a->sign; return r; }\n    LBig r = lbig_sub_mag(b, a); if (r.len) r.sign = b->sign; return r;\n}\nstatic LBig lbig_neg(const LBig *a) { LBig r = lbig_copy(a); if (r.len) r.sign = -a->sign; return r; }\nstatic LBig lbig_sub(const LBig *a, const LBig *b) { LBig nb = lbig_neg(b); LBig r = lbig_add(a, &nb); lbig_free(&nb); return r; }\nstatic LBig lbig_mul(const LBig *a, const LBig *b) {\n    if (a->sign == 0 || b->sign == 0) return lbig_make(1);\n    LBig r = lbig_make(a->len + b->len);\n    for (size_t i = 0; i < a->len; i++) {\n        uint64_t carry = 0;\n        for (size_t j = 0; j < b->len; j++) {\n            uint64_t cur = (uint64_t)r.limb[i + j] + (uint64_t)a->limb[i] * b->limb[j] + carry;\n            r.limb[i + j] = (uint32_t)(cur % LBIG_BASE);\n            carry = cur / LBIG_BASE;\n        }\n        r.limb[i + b->len] += (uint32_t)carry;\n    }\n    r.len = a->len + b->len; r.sign = a->sign * b->sign; lbig_trim(&r);\n    return r;\n}\nstatic LBig lbig_pow(const LBig *base, uint64_t exp) {\n    LBig result = lbig_from_i64(1);\n    LBig b = lbig_copy(base);\n    while (exp > 0) {\n        if (exp & 1) { LBig t = lbig_mul(&result, &b); lbig_free(&result); result = t; }\n        exp >>= 1;\n        if (exp) { LBig t = lbig_mul(&b, &b); lbig_free(&b); b = t; }\n    }\n    lbig_free(&b);\n    return result;\n}\nstatic int lbig_cmp(const LBig *a, const LBig *b) {\n    if (a->sign != b->sign) return a->sign < b->sign ? -1 : 1;\n    int m = lbig_cmp_mag(a, b);\n    return a->sign < 0 ? -m : m; /* for negatives, larger magnitude = smaller value */\n}\nstatic char *lbig_to_string(const LBig *a) {\n    if (a->len == 0) { char *z = (char *)lc_gc_alloc_atomic(2); z[0] = \'0\'; z[1] = \'\\0\'; return z; }\n    char *buf = (char *)lc_gc_alloc_atomic(a->len * 9 + 2);\n    char *p = buf;\n    if (a->sign < 0) *p++ = \'-\';\n    p += sprintf(p, \"%u\", a->limb[a->len - 1]);\n    for (size_t i = a->len - 1; i-- > 0; ) p += sprintf(p, \"%09u\", a->limb[i]);\n    *p = \'\\0\';\n    return buf;\n}\nstatic void show_bignum(LBig a) { char *s = lbig_to_string(&a); printf(\"%s\\n\", s); lc_gc_free(s); }\n\n/* ================= Exact rational + complex tower over LBig ==================\n   The AOT-Rust backend keeps exact LogosRational / LogosComplex; the C backend now\n   mirrors them so `decimal`/`complex` are byte-identical on every tier. Built on LBig:\n   binary GCD (no long division needed) + a per-limb binary-search divmod for reduction. */\n__attribute__((unused)) static int lbig_is_even(const LBig *a) { return a->len == 0 ? 1 : (a->limb[0] % 2 == 0); }\n__attribute__((unused)) static LBig lbig_halve(const LBig *a) { /* |a|/2, sign kept */\n    LBig r = lbig_make(a->len ? a->len : 1); uint64_t rem = 0;\n    for (size_t i = a->len; i-- > 0; ) { uint64_t cur = rem * LBIG_BASE + a->limb[i]; r.limb[i] = (uint32_t)(cur / 2); rem = cur % 2; }\n    r.len = a->len; r.sign = a->sign; lbig_trim(&r); return r;\n}\n__attribute__((unused)) static LBig lbig_double(const LBig *a) { /* |a|*2, sign kept */\n    LBig r = lbig_make(a->len + 1); uint64_t carry = 0;\n    for (size_t i = 0; i < a->len; i++) { uint64_t cur = (uint64_t)a->limb[i] * 2 + carry; r.limb[i] = (uint32_t)(cur % LBIG_BASE); carry = cur / LBIG_BASE; }\n    r.limb[a->len] = (uint32_t)carry; r.len = a->len + 1; r.sign = a->sign; lbig_trim(&r); return r;\n}\n/* gcd of magnitudes (result sign 0/1), binary/Stein \u{2014} shifts+subtraction, no division. */\n__attribute__((unused)) static LBig lbig_gcd(const LBig *x, const LBig *y) {\n    LBig a = lbig_copy(x); if (a.len) a.sign = 1; LBig b = lbig_copy(y); if (b.len) b.sign = 1;\n    if (a.len == 0) { lbig_free(&a); return b; } if (b.len == 0) { lbig_free(&b); return a; }\n    size_t shift = 0;\n    while (lbig_is_even(&a) && lbig_is_even(&b)) { LBig t = lbig_halve(&a); lbig_free(&a); a = t; t = lbig_halve(&b); lbig_free(&b); b = t; shift++; }\n    while (lbig_is_even(&a)) { LBig t = lbig_halve(&a); lbig_free(&a); a = t; }\n    do {\n        while (lbig_is_even(&b)) { LBig t = lbig_halve(&b); lbig_free(&b); b = t; }\n        if (lbig_cmp_mag(&a, &b) > 0) { LBig t = a; a = b; b = t; }\n        LBig nb = lbig_sub_mag(&b, &a); lbig_free(&b); b = nb;\n    } while (b.len != 0);\n    lbig_free(&b);\n    for (size_t i = 0; i < shift; i++) { LBig t = lbig_double(&a); lbig_free(&a); a = t; }\n    return a;\n}\n__attribute__((unused)) static LBig lbig_mul_small(const LBig *a, uint32_t m) {\n    if (a->sign == 0 || m == 0) return lbig_make(1);\n    LBig r = lbig_make(a->len + 2); uint64_t carry = 0; size_t i;\n    for (i = 0; i < a->len; i++) { uint64_t cur = (uint64_t)a->limb[i] * m + carry; r.limb[i] = (uint32_t)(cur % LBIG_BASE); carry = cur / LBIG_BASE; }\n    while (carry) { r.limb[i++] = (uint32_t)(carry % LBIG_BASE); carry /= LBIG_BASE; }\n    r.len = i; r.sign = a->sign; lbig_trim(&r); return r;\n}\n/* magnitude long division A/D via per-limb binary search: q outputs floor(|A|/|D|), *rem gets |A|%|D|. */\n__attribute__((unused)) static LBig lbig_divmod_mag(const LBig *A, const LBig *D, LBig *rem) {\n    LBig q = lbig_make(A->len ? A->len : 1); q.len = A->len; q.sign = 1;\n    LBig r = lbig_make(1); /* running remainder, magnitude */\n    for (size_t i = A->len; i-- > 0; ) {\n        LBig sh = lbig_mul_small(&r, (uint32_t)LBIG_BASE); lbig_free(&r); r = sh; /* r *= BASE */\n        if (A->limb[i]) { LBig dig = lbig_from_u64(A->limb[i]); LBig s = lbig_add_mag(&r, &dig); lbig_free(&dig); lbig_free(&r); r = s; }\n        uint32_t lo = 0, hi = (uint32_t)LBIG_BASE - 1, qd = 0;\n        while (lo <= hi) { uint32_t mid = lo + (hi - lo) / 2; LBig t = lbig_mul_small(D, mid);\n            int c = lbig_cmp_mag(&t, &r); lbig_free(&t);\n            if (c <= 0) { qd = mid; if (mid == (uint32_t)LBIG_BASE - 1) break; lo = mid + 1; } else { if (mid == 0) break; hi = mid - 1; } }\n        q.limb[i] = qd;\n        if (qd) { LBig t = lbig_mul_small(D, qd); LBig nr = lbig_sub_mag(&r, &t); lbig_free(&t); lbig_free(&r); r = nr; }\n    }\n    lbig_trim(&q); if (q.len == 0) q.sign = 0;\n    if (rem) { lbig_trim(&r); if (r.len == 0) r.sign = 0; *rem = r; } else lbig_free(&r);\n    return q;\n}\n/* exact quotient |a|/|g| (g divides a); sign 0/1. */\n__attribute__((unused)) static LBig lbig_divexact(const LBig *a, const LBig *g) { return lbig_divmod_mag(a, g, NULL); }\n/* The double nearest to `a`, ties to even, infinite once the rounding reaches 2^1024 \u{2014} the definition is\n   `logicaffeine_base::BigInt::to_f64`, and `c_bigint_to_f64_lock` holds this twin to it. The magnitude is\n   re-based to base 2^32 exactly; its top 64 significant bits are taken with every lower bit folded into\n   bit 0 as a sticky bit (eleven places under the 53-bit rounding position), converted once, and scaled\n   back by a power of two, which is exact until it overflows. */\n__attribute__((unused)) static double lbig_to_f64(const LBig *a) {\n    if (a->len == 0) return 0.0;\n    uint32_t *w = (uint32_t *)lc_gc_calloc_atomic(a->len + 1, sizeof(uint32_t));\n    size_t n = 0;\n    for (size_t i = a->len; i-- > 0; ) {\n        uint64_t carry = a->limb[i];\n        for (size_t j = 0; j < n; j++) {\n            uint64_t t = (uint64_t)w[j] * LBIG_BASE + carry;\n            w[j] = (uint32_t)t;\n            carry = t >> 32;\n        }\n        if (carry) w[n++] = (uint32_t)carry; /* < 10^9 + 1: one word */\n    }\n    uint64_t bits = (uint64_t)(n - 1) * 32 + (uint64_t)(32 - __builtin_clz(w[n - 1]));\n    double r;\n    if (bits <= 64) {\n        r = (double)((uint64_t)w[0] | (n > 1 ? (uint64_t)w[1] << 32 : 0));\n    } else {\n        uint64_t dropped = bits - 64, top = 0;\n        for (uint64_t k = 0; k < 64; k++) {\n            uint64_t bit = dropped + k;\n            top |= (uint64_t)((w[bit / 32] >> (bit % 32)) & 1u) << k;\n        }\n        int sticky = 0;\n        for (uint64_t word = 0; word < dropped / 32 && !sticky; word++) sticky = w[word] != 0;\n        if (!sticky && dropped % 32) sticky = (w[dropped / 32] & ((1u << (dropped % 32)) - 1u)) != 0;\n        r = ldexp((double)(top | (uint64_t)sticky), (int)dropped);\n    }\n    lc_gc_free(w);\n    return a->sign < 0 ? -r : r;\n}\n\n/* ===== Decimal (scale-aware) \u{2014} the C mirror of the interpreter\'s Decimal|Rational union. A value is\n   either a FIXED-POINT decimal (`a / 10^scale`, is_rat=0) or, once a non-terminating division occurs,\n   a REDUCED FRACTION (`a / b`, b>0, is_rat=1) that stays a fraction through further arithmetic.\n   `decimal(\"0.10\")`\u{2192}\"0.10\"; `decimal(1)/decimal(3)`\u{2192}\"1/3\"; `1/3 + 1/6`\u{2192}\"1/2\". By-value, built on LBig. */\ntypedef struct { int is_rat; LBig a; LBig b; int scale; } LDec;\n__attribute__((unused)) static LBig lbig_pow10(int k) {\n    LBig r = lbig_from_i64(1), ten = lbig_from_i64(10);\n    for (int i = 0; i < k; i++) { LBig t = lbig_mul(&r, &ten); lbig_free(&r); r = t; }\n    lbig_free(&ten); return r;\n}\n/* exact division `n / d` (d divides n); the quotient carries n\'s sign. */\n__attribute__((unused)) static LBig lbig_exact_div(const LBig *n, const LBig *d) {\n    LBig rem; LBig q = lbig_divmod_mag(n, d, &rem); lbig_free(&rem); q.sign = q.len ? n->sign : 0; return q;\n}\n__attribute__((unused)) static LDec ldec_from_i64(int64_t v) {\n    LDec d; d.is_rat = 0; d.a = lbig_from_i64(v); d.b = lbig_from_i64(0); d.scale = 0; return d;\n}\n/* (num, den) view of a decimal \u{2014} the caller owns the returned copies. */\n__attribute__((unused)) static void ldec_as_rat(const LDec *d, LBig *num, LBig *den) {\n    *num = lbig_copy(&d->a);\n    *den = d->is_rat ? lbig_copy(&d->b) : lbig_pow10(d->scale);\n}\n/* reduce `num/den` to lowest terms with den>0; CONSUMES num & den \u{2192} a rational-form LDec. */\n__attribute__((unused)) static LDec ldec_rat(LBig num, LBig den) {\n    if (den.len == 0) logos_fatal(\"decimal divide by zero\");\n    LBig g = lbig_gcd(&num, &den);\n    LBig rn = lbig_exact_div(&num, &g), rd = lbig_exact_div(&den, &g);\n    lbig_free(&num); lbig_free(&den); lbig_free(&g);\n    if (rd.sign < 0) { rd.sign = 1; if (rn.len) rn.sign = -rn.sign; }\n    LDec d; d.is_rat = 1; d.a = rn; d.b = rd; d.scale = 0; return d;\n}\n__attribute__((unused)) static LDec ldec_add(LDec x, LDec y) {\n    if (!x.is_rat && !y.is_rat) {\n        int s = x.scale > y.scale ? x.scale : y.scale;\n        LBig px = lbig_pow10(s - x.scale), py = lbig_pow10(s - y.scale);\n        LBig xa = lbig_mul(&x.a, &px), ya = lbig_mul(&y.a, &py), sum = lbig_add(&xa, &ya);\n        lbig_free(&px); lbig_free(&py); lbig_free(&xa); lbig_free(&ya);\n        LDec d; d.is_rat = 0; d.a = sum; d.b = lbig_from_i64(0); d.scale = s; return d;\n    }\n    LBig xn, xd, yn, yd; ldec_as_rat(&x, &xn, &xd); ldec_as_rat(&y, &yn, &yd);\n    LBig t1 = lbig_mul(&xn, &yd), t2 = lbig_mul(&yn, &xd), num = lbig_add(&t1, &t2), den = lbig_mul(&xd, &yd);\n    lbig_free(&xn); lbig_free(&xd); lbig_free(&yn); lbig_free(&yd); lbig_free(&t1); lbig_free(&t2);\n    return ldec_rat(num, den);\n}\n__attribute__((unused)) static LDec ldec_sub(LDec x, LDec y) {\n    if (!x.is_rat && !y.is_rat) {\n        int s = x.scale > y.scale ? x.scale : y.scale;\n        LBig px = lbig_pow10(s - x.scale), py = lbig_pow10(s - y.scale);\n        LBig xa = lbig_mul(&x.a, &px), ya = lbig_mul(&y.a, &py), diff = lbig_sub(&xa, &ya);\n        lbig_free(&px); lbig_free(&py); lbig_free(&xa); lbig_free(&ya);\n        LDec d; d.is_rat = 0; d.a = diff; d.b = lbig_from_i64(0); d.scale = s; return d;\n    }\n    LBig xn, xd, yn, yd; ldec_as_rat(&x, &xn, &xd); ldec_as_rat(&y, &yn, &yd);\n    LBig t1 = lbig_mul(&xn, &yd), t2 = lbig_mul(&yn, &xd), num = lbig_sub(&t1, &t2), den = lbig_mul(&xd, &yd);\n    lbig_free(&xn); lbig_free(&xd); lbig_free(&yn); lbig_free(&yd); lbig_free(&t1); lbig_free(&t2);\n    return ldec_rat(num, den);\n}\n__attribute__((unused)) static LDec ldec_mul(LDec x, LDec y) {\n    if (!x.is_rat && !y.is_rat) {\n        LBig prod = lbig_mul(&x.a, &y.a);\n        LDec d; d.is_rat = 0; d.a = prod; d.b = lbig_from_i64(0); d.scale = x.scale + y.scale; return d;\n    }\n    LBig xn, xd, yn, yd; ldec_as_rat(&x, &xn, &xd); ldec_as_rat(&y, &yn, &yd);\n    LBig num = lbig_mul(&xn, &yn), den = lbig_mul(&xd, &yd);\n    lbig_free(&xn); lbig_free(&xd); lbig_free(&yn); lbig_free(&yd);\n    return ldec_rat(num, den);\n}\n__attribute__((unused)) static LDec ldec_div(LDec x, LDec y) {\n    LBig xn, xd, yn, yd; ldec_as_rat(&x, &xn, &xd); ldec_as_rat(&y, &yn, &yd);\n    LBig num = lbig_mul(&xn, &yd), den = lbig_mul(&xd, &yn);\n    lbig_free(&xn); lbig_free(&xd); lbig_free(&yn); lbig_free(&yd);\n    return ldec_rat(num, den);\n}\n__attribute__((unused)) static char *ldec_to_string(const LDec *d) {\n    if (d->is_rat) {\n        char *n = lbig_to_string(&d->a);\n        LBig one = lbig_from_i64(1);\n        int den_is_one = (lbig_cmp_mag(&d->b, &one) == 0);\n        lbig_free(&one);\n        if (den_is_one) return n;\n        char *den = lbig_to_string(&d->b);\n        char *out = (char *) lc_gc_alloc_atomic(strlen(n) + strlen(den) + 2);\n        sprintf(out, \"%s/%s\", n, den); lc_gc_free(n); lc_gc_free(den); return out;\n    }\n    int neg = (d->a.sign < 0);\n    LBig abs = lbig_copy(&d->a); if (abs.len) abs.sign = 1;\n    char *mag = lbig_to_string(&abs); lbig_free(&abs);\n    int mlen = (int) strlen(mag);\n    if (d->scale == 0) {\n        char *out = (char *) lc_gc_alloc_atomic(mlen + 2); int p = 0;\n        if (neg) out[p++] = \'-\'; strcpy(out + p, mag); lc_gc_free(mag); return out;\n    }\n    int total = mlen > d->scale ? mlen : d->scale + 1;   /* ensure >= 1 integer digit */\n    int intlen = total - d->scale, pad = total - mlen;\n    char *out = (char *) lc_gc_alloc_atomic(total + 3); int p = 0;\n    if (neg) out[p++] = \'-\';\n    for (int i = 0; i < intlen; i++) { int di = i - pad; out[p++] = (di < 0) ? \'0\' : mag[di]; }\n    out[p++] = \'.\';\n    for (int i = intlen; i < total; i++) { int di = i - pad; out[p++] = (di < 0) ? \'0\' : mag[di]; }\n    out[p] = 0; lc_gc_free(mag); return out;\n}\n__attribute__((unused)) static void show_ldec(LDec d) { char *s = ldec_to_string(&d); printf(\"%s\\n\", s); lc_gc_free(s); }\n/* Sign-correct three-way compare of two exact values (rational OR decimal). Cross-multiply over the\n   (num, den>0) view: x <=> y  \u{27fa}  xn\u{b7}yd <=> yn\u{b7}xd. Mirrors the interpreter\'s `Rational`/`Decimal` Ord. */\n__attribute__((unused)) static int ldec_cmp(LDec x, LDec y) {\n    LBig xn, xd, yn, yd; ldec_as_rat(&x, &xn, &xd); ldec_as_rat(&y, &yn, &yd);\n    LBig l = lbig_mul(&xn, &yd), r = lbig_mul(&yn, &xd);\n    int c = lbig_cmp(&l, &r);\n    lbig_free(&xn); lbig_free(&xd); lbig_free(&yn); lbig_free(&yd); lbig_free(&l); lbig_free(&r);\n    return c;\n}\n/* |value| \u{2014} the sign of the numerator/mantissa cleared, the exact form (rational vs decimal) kept. */\n__attribute__((unused)) static LDec ldec_abs(LDec x) {\n    LDec r; r.is_rat = x.is_rat; r.a = lbig_copy(&x.a); if (r.a.len) r.a.sign = 1;\n    r.b = lbig_copy(&x.b); r.scale = x.scale; return r;\n}\n/* floor: the greatest integer \u{2264} x, toward \u{2212}\u{221e} (a negative non-integer drops one below truncation). */\n__attribute__((unused)) static LBig ldec_floor(LDec x) {\n    LBig num, den; ldec_as_rat(&x, &num, &den);\n    LBig rem; LBig q = lbig_divmod_mag(&num, &den, &rem);\n    if (q.len) q.sign = num.sign;\n    if (num.sign < 0 && rem.len) { LBig one = lbig_from_i64(1); LBig q2 = lbig_sub(&q, &one); lbig_free(&q); lbig_free(&one); q = q2; }\n    lbig_free(&num); lbig_free(&den); lbig_free(&rem); return q;\n}\n/* ceil: the least integer \u{2265} x, toward +\u{221e} (a positive non-integer adds one above truncation). */\n__attribute__((unused)) static LBig ldec_ceil(LDec x) {\n    LBig num, den; ldec_as_rat(&x, &num, &den);\n    LBig rem; LBig q = lbig_divmod_mag(&num, &den, &rem);\n    if (q.len) q.sign = num.sign;\n    if (num.sign > 0 && rem.len) { LBig one = lbig_from_i64(1); LBig q2 = lbig_add(&q, &one); lbig_free(&q); lbig_free(&one); q = q2; }\n    lbig_free(&num); lbig_free(&den); lbig_free(&rem); return q;\n}\n/* round: nearest integer, HALF AWAY FROM ZERO (`7/2 \u{2192} 4`, `-7/2 \u{2192} -4`) \u{2014} the interpreter\'s `Rational::round`\n   (HalfUp), which matches Rust\'s `f64::round`. Rounds up in magnitude when 2\u{b7}|rem| \u{2265} den. */\n__attribute__((unused)) static LBig ldec_round(LDec x) {\n    LBig num, den; ldec_as_rat(&x, &num, &den);\n    LBig rem; LBig q = lbig_divmod_mag(&num, &den, &rem);\n    LBig two = lbig_from_i64(2), rem2 = lbig_mul(&rem, &two);\n    if (lbig_cmp_mag(&rem2, &den) >= 0) { LBig one = lbig_from_i64(1); LBig q2 = lbig_add(&q, &one); lbig_free(&q); lbig_free(&one); q = q2; }\n    if (q.len) q.sign = num.sign;\n    lbig_free(&num); lbig_free(&den); lbig_free(&rem); lbig_free(&two); lbig_free(&rem2); return q;\n}\n/* rescale a decimal to exactly `target` fractional digits, banker\'s rounding (round-half-even). */\n__attribute__((unused)) static LDec ldec_rescale(LDec d, int target) {\n    LBig num, den; ldec_as_rat(&d, &num, &den);\n    LBig p = lbig_pow10(target), n2 = lbig_mul(&num, &p);\n    lbig_free(&num); lbig_free(&p);\n    int neg = (n2.sign < 0); LBig nabs = n2; if (nabs.len) nabs.sign = 1;\n    LBig r; LBig q = lbig_divmod_mag(&nabs, &den, &r);\n    LBig two = lbig_from_i64(2), r2 = lbig_mul(&r, &two); lbig_free(&two);\n    int cmp = lbig_cmp_mag(&r2, &den), roundup = 0;\n    if (cmp > 0) roundup = 1;\n    else if (cmp == 0) roundup = (q.len && (q.limb[0] & 1u));   /* tie \u{2192} round to even */\n    lbig_free(&r2); lbig_free(&r); lbig_free(&nabs); lbig_free(&den);\n    if (roundup) { LBig one = lbig_from_i64(1), q2 = lbig_add(&q, &one); lbig_free(&one); lbig_free(&q); q = q2; }\n    if (neg && q.len) q.sign = -1;\n    LDec out; out.is_rat = 0; out.a = q; out.b = lbig_from_i64(0); out.scale = target; return out;\n}\n\n/* ===== Tagged big integer for LOGOS `Int` \u{2014} int64 fast path, LBig on overflow =====\n   The C mirror of the Rust backend\'s `LogosInt` (enum Small(i64)|Big). `big == NULL` means the value\n   IS `small` (the common, register-cheap case); otherwise the value is `*big`. Arithmetic stays raw\n   i64 while it provably fits (via `__builtin_*_overflow`) and promotes to LBig exactly on overflow, so\n   `10000000000 * 10000000000` is decimal-exact where raw `int64_t` wraps. Codegen-facing, BY VALUE. */\ntypedef struct { int64_t small; LBig *big; } LInt;\n__attribute__((unused)) static LInt lint_small(int64_t v) { LInt r; r.small = v; r.big = NULL; return r; }\n__attribute__((unused)) static LInt lint_big(LBig b) { LInt r; r.small = 0; r.big = (LBig *)lc_gc_alloc(sizeof(LBig)); *r.big = b; return r; }\n__attribute__((unused)) static LBig lint_as_big(LInt a) { return a.big ? lbig_copy(a.big) : lbig_from_i64(a.small); }\n/* An exact integer as the `LDec` it is, for exact arithmetic with a fraction. */\n__attribute__((unused)) static LDec ldec_from_lint(LInt v) { LDec d; d.is_rat = 0; d.a = lint_as_big(v); d.b = lbig_from_i64(0); d.scale = 0; return d; }\n/* normalize an LBig result back to a small when it fits i64 (keeps the fast path sticky). */\n__attribute__((unused)) static LInt lint_norm(LBig b) {\n    if (b.len <= 2) { /* < 10^18 in magnitude \u{2192} surely fits i64 */\n        int64_t v = 0; for (size_t i = b.len; i-- > 0; ) v = v * (int64_t)LBIG_BASE + (int64_t)b.limb[i];\n        if (b.sign < 0) v = -v; lbig_free(&b); return lint_small(v);\n    }\n    if (b.len == 3) { /* 10^18..10^27: may or may not fit \u{2014} compare against i64 bounds via f64 guard then exact */\n        double approx = lbig_to_f64(&b);\n        if (approx >= -9.2e18 && approx <= 9.2e18) {\n            /* borderline \u{2014} rebuild and range-check exactly is overkill; fall through to big form when unsure */\n        }\n    }\n    return lint_big(b);\n}\n__attribute__((unused)) static LInt lint_add(LInt a, LInt b) {\n    if (!a.big && !b.big) { int64_t r; if (!__builtin_add_overflow(a.small, b.small, &r)) return lint_small(r); }\n    LBig x = lint_as_big(a), y = lint_as_big(b), s = lbig_add(&x, &y); lbig_free(&x); lbig_free(&y); return lint_norm(s);\n}\n__attribute__((unused)) static LInt lint_sub(LInt a, LInt b) {\n    if (!a.big && !b.big) { int64_t r; if (!__builtin_sub_overflow(a.small, b.small, &r)) return lint_small(r); }\n    LBig x = lint_as_big(a), y = lint_as_big(b), s = lbig_sub(&x, &y); lbig_free(&x); lbig_free(&y); return lint_norm(s);\n}\n__attribute__((unused)) static LInt lint_mul(LInt a, LInt b) {\n    if (!a.big && !b.big) { int64_t r; if (!__builtin_mul_overflow(a.small, b.small, &r)) return lint_small(r); }\n    LBig x = lint_as_big(a), y = lint_as_big(b), s = lbig_mul(&x, &y); lbig_free(&x); lbig_free(&y); return lint_norm(s);\n}\n__attribute__((unused)) static int lint_cmp(LInt a, LInt b) {\n    if (!a.big && !b.big) return a.small < b.small ? -1 : (a.small > b.small ? 1 : 0);\n    LBig x = lint_as_big(a), y = lint_as_big(b); int c = lbig_cmp(&x, &y); lbig_free(&x); lbig_free(&y); return c;\n}\n/* Exact integer exponentiation \u{2014} the C mirror of the interpreter\'s promote-on-overflow `**`/`pow`.\n   Computes `base^exp` through the arbitrary-precision `LBig`, then `lint_norm`s the result so a value\n   that still fits i64 stays a fast small (`2**10 -> 1024`) and one that overflows promotes\n   (`2**100 -> the exact 31-digit BigInt`). A negative exponent has no exact integer value, so it\n   aborts LOUDLY \u{2014} byte-for-byte the tree-walker/VM, which reject it rather than truncate. */\n__attribute__((unused)) static LInt lint_pow(LInt base, int64_t exp) {\n    if (exp < 0) logos_fatal(\"LOGOS runtime error: a negative Int exponent has no exact integer value\");\n    LBig b = lint_as_big(base), p = lbig_pow(&b, (uint64_t)exp); lbig_free(&b); return lint_norm(p);\n}\n/* truncating division / C-remainder, sign-correct, with an LBig fallback beyond i64. */\n__attribute__((unused)) static LInt lint_div(LInt a, LInt b) {\n    if (!a.big && !b.big && !(a.small == INT64_MIN && b.small == -1)) return lint_small(a.small / b.small);\n    LBig x = lint_as_big(a), y = lint_as_big(b); int sign = ((x.sign < 0) != (y.sign < 0)) ? -1 : 1;\n    LBig q = lbig_divmod_mag(&x, &y, NULL); if (q.len) q.sign = sign; lbig_free(&x); lbig_free(&y); return lint_norm(q);\n}\n__attribute__((unused)) static LInt lint_mod(LInt a, LInt b) {\n    if (!a.big && !b.big && !(a.small == INT64_MIN && b.small == -1)) return lint_small(a.small % b.small);\n    LBig x = lint_as_big(a), y = lint_as_big(b), rem; LBig q = lbig_divmod_mag(&x, &y, &rem); lbig_free(&q);\n    if (rem.len) rem.sign = x.sign; /* C remainder takes the dividend\'s sign */\n    lbig_free(&x); lbig_free(&y); return lint_norm(rem);\n}\n__attribute__((unused)) static char *lint_to_string(LInt a) { if (!a.big) { char *s = (char *)lc_gc_alloc_atomic(24); sprintf(s, \"%lld\", (long long)a.small); return s; } return lbig_to_string(a.big); }\n__attribute__((unused)) static void show_lint(LInt a) { char *s = lint_to_string(a); printf(\"%s\\n\", s); lc_gc_free(s); }\n__attribute__((unused)) static double lint_to_f64(LInt a) { return a.big ? lbig_to_f64(a.big) : (double)a.small; }\n/* An exact integer in one `long long` cell (a task\'s argument, a stepped call\'s argument or result): a value within 62\n   bits as 2v + 1, any other as the address of its collector-held big integer, whose low bit is clear. A zeroed cell\n   reads as 0. The cell holds the big integer for as long as the frame holding the cell is reached. */\n__attribute__((unused)) static inline long long lint_to_cell(LInt a) {\n    if (!a.big && a.small >= -((int64_t)1 << 62) && a.small < ((int64_t)1 << 62)) return (long long)(a.small * 2 + 1);\n    LBig *big = a.big ? a.big : lint_big(lbig_from_i64(a.small)).big;\n    return (long long)(intptr_t)big;\n}\n__attribute__((unused)) static inline LInt lint_of_cell(long long c) {\n    if (c & 1) return lint_small((int64_t)((c - 1) / 2));\n    LInt r; r.small = 0; r.big = (LBig *)(intptr_t)c; return r;\n}\n/* Word constructors reduce exact integers modulo 2^64. Unsigned multiply\n   and subtraction are defined modulo 2^64 for every magnitude and sign. */\n__attribute__((unused)) static inline uint64_t lint_word_bits(LInt a) {\n    if (!a.big) return (uint64_t)a.small;\n    uint64_t bits = 0;\n    for (size_t i = a.big->len; i-- > 0; )\n        bits = bits * (uint64_t)LBIG_BASE + (uint64_t)a.big->limb[i];\n    return a.big->sign < 0 ? (uint64_t)0 - bits : bits;\n}\n/* Narrow to i64 at an int64-only boundary (a `Seq_i64` slot, an int64 param, an index). LOUD \u{2014} a value\n   genuinely beyond i64 aborts rather than silently truncating (matches the Rust `expect_i64`). */\n__attribute__((unused, noinline)) static int64_t lint_expect_i64_big(LInt a);\n/* An exact integer as a machine word: inline while it is one, out of line when it holds a big integer. */\n__attribute__((unused)) static inline int64_t lint_expect_i64(LInt a) {\n    if (__builtin_expect(!a.big, 1)) return a.small;\n    return lint_expect_i64_big(a);\n}\n__attribute__((unused, noinline)) static int64_t lint_expect_i64_big(LInt a) {\n    if (a.big->len <= 2) { int64_t v = 0; for (size_t i = a.big->len; i-- > 0; ) v = v * (int64_t)LBIG_BASE + (int64_t)a.big->limb[i]; return a.big->sign < 0 ? -v : v; }\n    if (a.big->len == 3) { /* 10^18..10^27 \u{2014} range-check exactly against i64 bounds */\n        LBig lo = lbig_from_i64(INT64_MIN), hi = lbig_from_i64(INT64_MAX);\n        int in = lbig_cmp(a.big, &lo) >= 0 && lbig_cmp(a.big, &hi) <= 0; lbig_free(&lo); lbig_free(&hi);\n        if (in) { int64_t v = 0; for (size_t i = a.big->len; i-- > 0; ) v = v * (int64_t)LBIG_BASE + (int64_t)a.big->limb[i]; return a.big->sign < 0 ? -v : v; }\n    }\n    logos_fatal(\"LOGOS runtime error: integer value out of range for this int64 context\");\n}\n/* An exact integer as a collection\'s index: the machine word it fits, or the reference tier\'s refusal of an index past\n   one (`refusal`, the generator\'s copy of its sentence). */\n__attribute__((unused, noinline)) static int64_t lint_index_i64_big(LInt a, const char *refusal);\n__attribute__((unused)) static inline int64_t lint_index_i64(LInt a, const char *refusal) {\n    if (__builtin_expect(!a.big, 1)) return a.small;\n    return lint_index_i64_big(a, refusal);\n}\n__attribute__((unused, noinline)) static int64_t lint_index_i64_big(LInt a, const char *refusal) {\n    LBig lo = lbig_from_i64(INT64_MIN), hi = lbig_from_i64(INT64_MAX);\n    int in = lbig_cmp(a.big, &lo) >= 0 && lbig_cmp(a.big, &hi) <= 0; lbig_free(&lo); lbig_free(&hi);\n    if (!in) logos_fatal(refusal);\n    return lint_expect_i64(a);\n}\n/* promote any int64 value into an LInt for mixed BigInt arithmetic. */\n__attribute__((unused)) static LInt lint_of(int64_t v) { return lint_small(v); }\n__attribute__((unused)) static inline int lint_is_zero(LInt a) { return !a.big && a.small == 0; }\n/* Whether the exact integer is within i64 \u{2014} what the VM holds as an `Int` \u{2014} and its value when it is. */\n__attribute__((unused)) static int lint_i64(LInt a, int64_t *v) {\n    if (!a.big) { *v = a.small; return 1; }\n    LBig lo = lbig_from_i64(INT64_MIN), hi = lbig_from_i64(INT64_MAX);\n    int in = lbig_cmp(a.big, &lo) >= 0 && lbig_cmp(a.big, &hi) <= 0; lbig_free(&lo); lbig_free(&hi);\n    if (in) *v = lint_expect_i64(a);\n    return in;\n}\n/* The bitwise operations over exact integers: within i64 they are the machine\'s; past it the VM refuses them \u{2014}\n   save a low-bit mask `2^k - 1` over a non-negative integer, which is its remainder by `2^k`. */\n__attribute__((unused)) static int64_t lint_bitand(LInt a, LInt b) {\n    int64_t x, y; int fx = lint_i64(a, &x), fy = lint_i64(b, &y);\n    if (fx && fy) return x & y;\n    if (fx != fy) {\n        int64_t m = fx ? x : y; LInt big = fx ? b : a;\n        if (m >= 0 && ((((uint64_t)m) + 1u) & (uint64_t)m) == 0 && lint_cmp(big, lint_small(0)) >= 0)\n            return lint_expect_i64(lint_mod(big, lint_add(lint_small(m), lint_small(1))));\n    }\n    logos_fatal(logos_says_bitand_refused);\n}\n__attribute__((unused)) static int64_t lint_bitor(LInt a, LInt b) { int64_t x, y; if (lint_i64(a, &x) && lint_i64(b, &y)) return x | y; logos_fatal(logos_says_bitor_refused); }\n__attribute__((unused)) static int64_t lint_bitxor(LInt a, LInt b) { int64_t x, y; if (lint_i64(a, &x) && lint_i64(b, &y)) return x ^ y; logos_fatal(logos_says_bitxor_refused); }\n__attribute__((unused)) static int64_t lint_shl(LInt a, LInt b) { int64_t x, y; if (lint_i64(a, &x) && lint_i64(b, &y)) return (int64_t)((uint64_t)x << ((uint32_t)y & 63u)); logos_fatal(logos_says_shl_refused); }\n__attribute__((unused)) static int64_t lint_shr(LInt a, LInt b) { int64_t x, y; if (lint_i64(a, &x) && lint_i64(b, &y)) return x >> ((uint32_t)y & 63u); logos_fatal(logos_says_shr_refused); }\n\n/* ===== An exact number as the VM holds it. The VM keeps a whole rational as the integer it equals\n   (`RuntimeValue::from_rational`), so a rational here answers `/`, `//`, `%`, `**`, the bitwise operators, an index\n   and a range bound by its value: a whole one as that integer does, a fraction by the rational rules, each refusal\n   in the VM\'s words. Operands are `LDec`s of an integer or a ratio; an integer operand comes in through\n   `ldec_from_lint`. ===== */\n__attribute__((unused)) static int ldec_whole(const LDec *d) {\n    if (d->is_rat) return d->b.len == 1 && d->b.limb[0] == 1;\n    if (d->scale == 0) return 1;\n    LBig p = lbig_pow10(d->scale), rem; LBig q = lbig_divmod_mag(&d->a, &p, &rem);\n    int whole = rem.len == 0; lbig_free(&p); lbig_free(&q); lbig_free(&rem); return whole;\n}\n/* The integer a whole exact number equals. */\n__attribute__((unused)) static LInt ldec_integer(const LDec *d) {\n    LBig num, den; ldec_as_rat(d, &num, &den);\n    LBig q = lbig_exact_div(&num, &den);\n    lbig_free(&num); lbig_free(&den); return lint_norm(q);\n}\n__attribute__((unused)) static inline int ldec_is_zero(const LDec *d) { return d->a.len == 0; }\n/* The double the VM converts an exact number to: numerator over denominator, each rounded once. */\n__attribute__((unused)) static double ldec_to_f64(LDec d) {\n    LBig num, den; ldec_as_rat(&d, &num, &den);\n    double v = lbig_to_f64(&num) / lbig_to_f64(&den);\n    lbig_free(&num); lbig_free(&den); return v;\n}\n/* `x / y`: two whole numbers divide as integers, toward zero; a fraction divides exactly. */\n__attribute__((unused)) static LDec ldec_quotient(LDec x, LDec y) {\n    if (ldec_whole(&x) && ldec_whole(&y)) {\n        LInt b = ldec_integer(&y);\n        if (lint_is_zero(b)) logos_fatal(logos_says_division_by_zero);\n        return ldec_from_lint(lint_div(ldec_integer(&x), b));\n    }\n    if (ldec_is_zero(&y)) logos_fatal(logos_says_rational_division_by_zero);\n    return ldec_div(x, y);\n}\n/* `x // y`: the floor of the exact quotient. */\n__attribute__((unused)) static LDec ldec_floor_quotient(LDec x, LDec y) {\n    if (ldec_is_zero(&y)) logos_fatal(logos_says_exact_floor_division_by_zero);\n    return ldec_from_lint(lint_norm(ldec_floor(ldec_div(x, y))));\n}\n/* `x % y`: two whole numbers take the integer remainder, carrying the dividend\'s sign; a fraction has none. */\n__attribute__((unused)) static LDec ldec_remainder(LDec x, LDec y) {\n    int wx = ldec_whole(&x), wy = ldec_whole(&y);\n    if (wx && wy) {\n        LInt b = ldec_integer(&y);\n        if (lint_is_zero(b)) logos_fatal(logos_says_modulo_by_zero);\n        return ldec_from_lint(lint_mod(ldec_integer(&x), b));\n    }\n    if (wx) logos_fatal(logos_says_modulo_int_rational);\n    if (wy) logos_fatal(logos_says_modulo_rational_int);\n    logos_fatal(logos_says_modulo_rational_rational);\n}\n/* `base ** exponent`: a whole base takes an integer\'s power, which has no negative exponent; a fraction takes any\n   exponent within i32; an exponent that is a fraction is refused. */\n__attribute__((unused)) static LDec ldec_power(LDec base, LDec exponent) {\n    int wb = ldec_whole(&base);\n    if (!ldec_whole(&exponent)) logos_fatal(wb ? logos_says_power_int_rational : logos_says_power_rational_rational);\n    LInt e = ldec_integer(&exponent);\n    if (wb) {\n        LInt b = ldec_integer(&base);\n        if (e.big) logos_fatal(logos_says_power_int_big);\n        if (!b.big) {\n            if (e.small < 0) logos_fatal(logos_says_negative_exponent);\n            if (e.small > (int64_t)UINT32_MAX) logos_fatal(logos_says_exponent_too_large);\n        } else if (e.small < 0 || e.small > (int64_t)UINT32_MAX) {\n            logos_fatal(logos_says_big_exponent);\n        }\n        return ldec_from_lint(lint_pow(b, e.small));\n    }\n    if (e.big) logos_fatal(logos_says_power_rational_big);\n    if (e.small < INT32_MIN || e.small > INT32_MAX) logos_fatal(logos_says_rational_exponent_too_large);\n    LBig num, den; ldec_as_rat(&base, &num, &den);\n    uint64_t k = e.small < 0 ? (uint64_t)(-e.small) : (uint64_t)e.small;\n    LBig pn = lbig_pow(&num, k), pd = lbig_pow(&den, k);\n    lbig_free(&num); lbig_free(&den);\n    return e.small < 0 ? ldec_rat(pd, pn) : ldec_rat(pn, pd);\n}\n/* `x & y`, `x | y`, `x ^ y`, `x << y`, `x >> y` (`op` \'&\', \'|\', \'^\', \'<\', \'>\'): two whole numbers as the integers\n   they are, a fraction refused. */\n__attribute__((unused)) static int64_t ldec_bitwise(LDec x, LDec y, char op) {\n    if (!ldec_whole(&x) || !ldec_whole(&y)) {\n        switch (op) {\n        case \'&\': logos_fatal(logos_says_bitand_fraction);\n        case \'|\': logos_fatal(logos_says_bitor_fraction);\n        case \'^\': logos_fatal(logos_says_bitxor_fraction);\n        case \'<\': logos_fatal(logos_says_shl_fraction);\n        default: logos_fatal(logos_says_shr_fraction);\n        }\n    }\n    LInt a = ldec_integer(&x), b = ldec_integer(&y);\n    switch (op) {\n    case \'&\': return lint_bitand(a, b);\n    case \'|\': return lint_bitor(a, b);\n    case \'^\': return lint_bitxor(a, b);\n    case \'<\': return lint_shl(a, b);\n    default: return lint_shr(a, b);\n    }\n}\n/* An exact number where the VM takes a machine integer \u{2014} an index, a range bound, a slice bound: a whole one within\n   i64 is that integer; one past it, or a fraction, is refused in the VM\'s words for the place (`past_word`,\n   `fraction`). */\n__attribute__((unused)) static int64_t ldec_as_i64(LDec d, const char *past_word, const char *fraction) {\n    if (!ldec_whole(&d)) logos_fatal(fraction);\n    int64_t i;\n    if (!lint_i64(ldec_integer(&d), &i)) logos_fatal(past_word);\n    return i;\n}\n/* The double `f`, exactly, as a ratio: its significand over a power of two. Finite `f` only. */\n__attribute__((unused)) static LDec ldec_of_f64(double f) {\n    int e; double m = frexp(f, &e);\n    int64_t sig = (int64_t)ldexp(m, 53); e -= 53;\n    LBig two = lbig_from_i64(2), num = lbig_from_i64(sig), den = lbig_from_i64(1);\n    LBig p = lbig_pow(&two, (uint64_t)(e < 0 ? -e : e)); lbig_free(&two);\n    if (e >= 0) { LBig t = lbig_mul(&num, &p); lbig_free(&num); num = t; } else { lbig_free(&den); den = lbig_copy(&p); }\n    lbig_free(&p);\n    return ldec_rat(num, den);\n}\n/* The order of an exact number against a double, exactly (`cmp_rational_f64_exact`): -1, 0 or 1, and 2 when `f` is\n   NaN, which orders against nothing. */\n__attribute__((unused)) static int ldec_cmp_f64(LDec x, double f) {\n    if (f != f) return 2;\n    if (f == INFINITY) return -1;\n    if (f == -INFINITY) return 1;\n    return ldec_cmp(x, ldec_of_f64(f));\n}\n\n\n/* ---- Rational: a handle to an exact number of the section above (an `LDec`), which follows the VM\'s rules for\n   two exact numbers \u{2014} a whole rational answers `/`, `%`, `//`, `**` and the bitwise operators as the integer it\n   equals. An operand is a rational handle (`flag` 1) or a machine Int (`flag` 0). ---- */\n\nstatic long long logos_ldec_box(LDec d) {\n    LDec *p = (LDec *)lc_gc_alloc(sizeof(LDec));\n    *p = d;\n    return (long long)p;\n}\n\nstatic LDec logos_ldec_of(long long v, int flag) { return flag ? *(const LDec *)v : ldec_from_i64(v); }\n\n/* An Int as the rational it equals. */\nlong long logos_ldec_of_int(long long v) { return logos_ldec_box(ldec_from_i64(v)); }\n\n/* `a op b`, a rational: op 0 `+`, 1 `-`, 2 `*`, 3 `/`, 4 the exact `/`, 5 `//`, 6 `%`, 7 `**`. */\nlong long logos_ldec_op(long long a, int af, long long b, int bf, int op) {\n    LDec x = logos_ldec_of(a, af), y = logos_ldec_of(b, bf);\n    switch (op) {\n        case 0: return logos_ldec_box(ldec_add(x, y));\n        case 1: return logos_ldec_box(ldec_sub(x, y));\n        case 2: return logos_ldec_box(ldec_mul(x, y));\n        case 3: return logos_ldec_box(ldec_quotient(x, y));\n        case 4:\n            if (ldec_is_zero(&y)) logos_fatal(logos_exact_division_refusal);\n            return logos_ldec_box(ldec_div(x, y));\n        case 5: return logos_ldec_box(ldec_floor_quotient(x, y));\n        case 6: return logos_ldec_box(ldec_remainder(x, y));\n        default: return logos_ldec_box(ldec_power(x, y));\n    }\n}\n\n/* `a & b`, `a | b`, `a ^ b`, `a << b`, `a >> b` (`op` \'&\', \'|\', \'^\', \'<\', \'>\') over two whole numbers, an Int. */\nlong long logos_ldec_bitwise(long long a, int af, long long b, int bf, int op) {\n    return ldec_bitwise(logos_ldec_of(a, af), logos_ldec_of(b, bf), (char)op);\n}\n\n/* The order of two exact numbers: -1, 0 or 1. */\nint logos_ldec_cmp(long long a, int af, long long b, int bf) { return ldec_cmp(logos_ldec_of(a, af), logos_ldec_of(b, bf)); }\n\n/* The order of a rational against a real by the real\'s exact value: -1, 0 or 1, and 2 when the real is NaN. */\nint logos_ldec_cmp_f64(long long a, double f) { return ldec_cmp_f64(*(const LDec *)a, f); }\n\n/* The double the VM converts a rational to beside a real. */\ndouble logos_ldec_to_f64(long long a) { return ldec_to_f64(*(const LDec *)a); }\n\n/* `a op f`, or `f op a` when the rational is on the right (`rational_left` 0), a rational beside a real, as the VM\n   computes it on the rational\'s double: op 0 `+`, 1 `-`, 2 `*`, 3 `/`, 4 `**`. */\ndouble logos_ldec_real_op(long long a, double f, int rational_left, int op) {\n    double x = ldec_to_f64(*(const LDec *)a);\n    double l = rational_left ? x : f, r = rational_left ? f : x;\n    switch (op) {\n        case 0: return l + r;\n        case 1: return l - r;\n        case 2: return l * r;\n        case 3:\n            if (r == 0.0) logos_fatal(logos_float_division_refusal);\n            return l / r;\n        default: return pow(l, r);\n    }\n}\n\n/* A rational where the VM takes a machine integer: the integer a whole one is, else the place\'s refusal. */\nlong long logos_ldec_as_i64(long long a, const char *past_word, const char *fraction) {\n    return ldec_as_i64(*(const LDec *)a, past_word, fraction);\n}\n\n/* `num/den`, or the integer a whole rational equals. */\nchar *logos_ldec_str(long long handle) { return ldec_to_string((const LDec *)handle); }\n\n/* ---- Temporal: Date (days since epoch) / Moment (nanos since epoch), \u{2261} the VM\'s Show ---- */\n\n/* Floored (Euclidean) division \u{2014} a pre-epoch Moment yields the correct date + a 0..86399 time-of-day. */\nstatic long long logos_fdiv(long long a, long long b) {\n    long long q = a / b;\n    if ((a % b != 0) && ((a < 0) != (b < 0))) q--;\n    return q;\n}\n\n/* Civil date from days-since-epoch (Howard Hinnant\'s algorithm, matching `RuntimeValue::Date`). */\nstatic void logos_civil(long long days, long long *year, long long *mon, long long *day) {\n    long long z = days + 719468;\n    long long era = (z >= 0 ? z : z - 146096) / 146097;\n    long long doe = z - era * 146097;\n    long long yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;\n    long long y = yoe + era * 400;\n    long long doy = doe - (365 * yoe + yoe / 4 - yoe / 100);\n    long long mp = (5 * doy + 2) / 153;\n    long long d = doy - (153 * mp + 2) / 5 + 1;\n    long long m = mp + (mp < 10 ? 3 : -9);\n    *year = y + (m <= 2 ? 1 : 0);\n    *mon = m;\n    *day = d;\n}\n\nchar *logos_date_str(long long days) {\n    long long y, m, d;\n    logos_civil(days, &y, &m, &d);\n    char *b = (char *)lc_gc_alloc_atomic(32);\n    snprintf(b, 32, \"%04lld-%02lld-%02lld\", y, m, d);\n    return b;\n}\n\nchar *logos_moment_str(long long nanos) {\n    long long total_seconds = logos_fdiv(nanos, 1000000000LL);\n    long long days = logos_fdiv(total_seconds, 86400LL);\n    long long day_seconds = total_seconds - days * 86400LL;\n    long long hours = day_seconds / 3600;\n    long long minutes = (day_seconds % 3600) / 60;\n    long long y, m, d;\n    logos_civil(days, &y, &m, &d);\n    char *b = (char *)lc_gc_alloc_atomic(48);\n    snprintf(b, 48, \"%04lld-%02lld-%02lld %02lld:%02lld\", y, m, d, hours, minutes);\n    return b;\n}\n\n/* `today` / `now` \u{2014} the injected fixed clock (env `LOGOS_FIXED_DAYS`/`LOGOS_FIXED_NANOS`, set by the\n   differential harness so the AOT binary and the VM oracle read the SAME instant) else the real clock. */\nlong long logos_today(void) {\n    const char *e = getenv(\"LOGOS_FIXED_DAYS\");\n    if (e) return atoll(e);\n    return (long long)(time(NULL) / 86400);\n}\n\nlong long logos_now(void) {\n    const char *e = getenv(\"LOGOS_FIXED_NANOS\");\n    if (e) return atoll(e);\n    return (long long)time(NULL) * 1000000000LL;\n}\n\n/* time.lg\'s `now()` \u{2014} the Unix time in milliseconds from the real clock, as the interpreter reads it. */\nlong long logos_time_now(void) {\n    struct timespec ts;\n    timespec_get(&ts, TIME_UTC);\n    return (long long)ts.tv_sec * 1000 + (long long)(ts.tv_nsec / 1000000);\n}\n\n/* env.lg\'s `get(name)`, in the halves the VM expands it into: whether the process environment sets the\n   variable, and its text (`\"\"` when it is unset). */\nlong long logos_env_has(const char *name) {\n    return getenv(name) != NULL;\n}\n\nchar *logos_env_value(const char *name) {\n    const char *v = getenv(name);\n    return lc_gc_strdup(v ? v : \"\");\n}\n\n/* How a cell of the exact extension displays, set by the extension\'s adapter when the shim embeds it\n   (`codegen_riscv::runtime`); a program that holds no cell never reads it. */\nstatic char *(*logos_tower_text_hook)(long long);\n\nchar *logos_val_to_str(long long bits, int kind) {\n    switch (kind) {\n        case 0: { char *b = (char *)lc_gc_alloc_atomic(24); snprintf(b, 24, \"%lld\", bits); return b; }\n        case 1: { double f; memcpy(&f, &bits, 8); return logos_fmt_f64(f); }\n        case 2: return lc_gc_strdup(bits ? \"true\" : \"false\");\n        case 4: return logos_ldec_str(bits); /* Rational */\n        case 5: return logos_date_str(bits); /* Date */\n        case 6: return logos_moment_str(bits); /* Moment */\n        case 7: return lc_gc_strdup(\"nothing\"); /* a value-or-nothing holding nothing */\n        case 8: { /* a PeerAgent: `<peer topic>` */\n            size_t n = strlen((const char *)bits) + 8;\n            char *b = (char *)lc_gc_alloc_atomic(n);\n            snprintf(b, n, \"<peer %s>\", (const char *)bits);\n            return b;\n        }\n        case 9: return logos_tower_text_hook(bits); /* a cell of the exact extension */\n        default: return lc_gc_strdup((const char *)bits); /* Text: copy so the result is independently owned */\n    }\n}\n\n/* ---- A Text a register owns: `t = t + v` in place ----\n   While a register\'s owned flag is set, its Text is a block of its own \u{2014} its length and capacity just before\n   the characters \u{2014} which an append grows in place, amortized. Any other Text is copied into such a block\n   first, so an alias never sees the change. The characters stay an ordinary C string. */\ntypedef struct { size_t len, cap; } logos_text_block;\n\n/* `t = t + v` into the register at `slot`: `v`\'s text by its kind tag. `v` is read before anything moves. */\nvoid logos_text_append_own(char **slot, long long *owned, long long v, int tag) {\n    char *made = tag == 3 ? NULL : logos_val_to_str(v, tag);\n    const char *add = made ? made : (const char *)v;\n    size_t n = strlen(add);\n    logos_text_block *b;\n    if (*owned) {\n        b = (logos_text_block *)*slot - 1;\n    } else {\n        size_t len = strlen(*slot);\n        b = (logos_text_block *)lc_gc_alloc_atomic(sizeof *b + len + n + 1);\n        b->len = len;\n        b->cap = len + n;\n        memcpy(b + 1, *slot, len + 1);\n        *owned = 1;\n    }\n    if (b->len + n > b->cap) {\n        size_t cap = b->cap * 2 > b->len + n ? b->cap * 2 : b->len + n;\n        b = (logos_text_block *)lc_gc_realloc_atomic(b, sizeof *b + cap + 1);\n        b->cap = cap;\n    }\n    memcpy((char *)(b + 1) + b->len, add, n + 1);\n    b->len += n;\n    *slot = (char *)(b + 1);\n    lc_gc_free(made);\n}\n\n/* `Op::Concat` \u{2014} stringify both operands (by kind) and join, matching the VM\'s `arith::concat`. */\nchar *logos_concat_vals(long long a, int ak, long long b, int bk) {\n    char *sa = logos_val_to_str(a, ak);\n    char *sb = logos_val_to_str(b, bk);\n    size_t la = strlen(sa), lb = strlen(sb);\n    char *out = (char *)lc_gc_alloc_atomic(la + lb + 1);\n    memcpy(out, sa, la);\n    memcpy(out + la, sb, lb);\n    out[la + lb] = \'\\0\';\n    lc_gc_free(sa);\n    lc_gc_free(sb);\n    return out;\n}\n\n/* `Show` of a Text value \u{2014} raw contents + newline, exactly like the VM. */\nvoid logos_show_text(const char *s) { printf(\"%s\\n\", s); }\n\n/* `Fail with <value>.` \u{2014} the value exactly as `Show` renders it. */\nvoid logos_fail_val(long long bits, int kind) { logos_fatal(logos_val_to_str(bits, kind)); }\n\n/* ---- Program arguments (`args()`) + `parseInt` ---- */\nstatic int logos_argc = 0;\nstatic char **logos_argv = NULL;\nvoid logos_set_args(int argc, char **argv) { logos_argc = argc; logos_argv = argv; }\n\n/* A failure naming a Text: `refusal` is a format of it (`%s`). */\n__attribute__((noreturn)) static void logos_fatals(const char *refusal, const char *text) {\n    size_t n = strlen(refusal) + strlen(text) + 1;\n    char *why = (char *)lc_gc_alloc_atomic(n);\n    snprintf(why, n, refusal, text);\n    logos_fatal(why);\n}\n\n/* `parseInt(t)` \u{2014} the VM\'s: `t` trimmed (`str::trim`), then the whole of it an `i64` in base 10 as\n   `str::parse` reads one (an optional sign, then digits, in range). Anything else stops the program with\n   `logos_parse_int_refusal`. */\nlong long logos_parse_int(const char *s) {\n    const char *refusal = logos_parse_int_refusal;\n    const char *p = logos_trim(s);\n    int negative = *p == \'-\';\n    if (*p == \'+\' || *p == \'-\') p++;\n    if (!*p) logos_fatals(refusal, s);\n    unsigned long long v = 0, limit = negative ? 9223372036854775808ULL : 9223372036854775807ULL;\n    for (; *p; p++) {\n        if (*p < \'0\' || *p > \'9\') logos_fatals(refusal, s);\n        unsigned long long d = (unsigned long long)(*p - \'0\');\n        if (v > (limit - d) / 10) logos_fatals(refusal, s);\n        v = v * 10 + d;\n    }\n    return negative ? (long long)(0 - v) : (long long)v;\n}\n\n/* Whether `s` spells `word`, ASCII case folded. */\nstatic int logos_ascii_is(const char *s, const char *word) {\n    for (; *word; s++, word++) {\n        char c = *s >= \'A\' && *s <= \'Z\' ? (char)(*s - \'A\' + \'a\') : *s;\n        if (c != *word) return 0;\n    }\n    return !*s;\n}\n\n/* `parseFloat(t)` \u{2014} the VM\'s: `t` trimmed, then the whole of it an `f64` as `str::parse` reads one: an\n   optional sign, then `inf`, `infinity` or `nan` in any case, or digits with at most one point among them\n   and at least one digit, then an optional exponent (`e`, an optional sign, digits). Anything else stops the\n   program with `logos_parse_float_refusal`. The value is the correctly rounded one (`strtod`). */\ndouble logos_parse_float(const char *s) {\n    const char *refusal = logos_parse_float_refusal;\n    const char *t = logos_trim(s), *p = t;\n    int negative = *p == \'-\';\n    if (*p == \'+\' || *p == \'-\') p++;\n    if (logos_ascii_is(p, \"inf\") || logos_ascii_is(p, \"infinity\")) return negative ? -INFINITY : INFINITY;\n    if (logos_ascii_is(p, \"nan\")) return negative ? -NAN : NAN;\n    int digits = 0;\n    while (*p >= \'0\' && *p <= \'9\') { p++; digits++; }\n    if (*p == \'.\') {\n        p++;\n        while (*p >= \'0\' && *p <= \'9\') { p++; digits++; }\n    }\n    if (!digits) logos_fatals(refusal, s);\n    if (*p == \'e\' || *p == \'E\') {\n        p++;\n        if (*p == \'+\' || *p == \'-\') p++;\n        if (!(*p >= \'0\' && *p <= \'9\')) logos_fatals(refusal, s);\n        while (*p >= \'0\' && *p <= \'9\') p++;\n    }\n    if (*p) logos_fatals(refusal, s);\n    return strtod(t, NULL);\n}\n\n/* `chr(codepoint)` \u{2014} a single-character UTF-8 Text handle, matching the VM\'s `char::from_u32`. */\nchar *logos_chr(long long cp) {\n    char *out = (char *)lc_gc_alloc_atomic(5);\n    unsigned int c = (unsigned int)cp;\n    int n = 0;\n    if (c < 0x80) { out[n++] = (char)c; }\n    else if (c < 0x800) { out[n++] = (char)(0xC0 | (c >> 6)); out[n++] = (char)(0x80 | (c & 0x3F)); }\n    else if (c < 0x10000) {\n        out[n++] = (char)(0xE0 | (c >> 12));\n        out[n++] = (char)(0x80 | ((c >> 6) & 0x3F));\n        out[n++] = (char)(0x80 | (c & 0x3F));\n    } else {\n        out[n++] = (char)(0xF0 | (c >> 18));\n        out[n++] = (char)(0x80 | ((c >> 12) & 0x3F));\n        out[n++] = (char)(0x80 | ((c >> 6) & 0x3F));\n        out[n++] = (char)(0x80 | (c & 0x3F));\n    }\n    out[n] = \'\\0\';\n    return out;\n}\n\n/* ---- CRDT counters (G-Counter / PN-Counter) \u{2014} a per-replica count map ---- */\n/* The observable is the SUM; merge/join take the per-replica MAX (IDEMPOTENT \u{2014} a redelivered state\n   never double-counts), so it converges regardless of order/duplication. The replica ids are drawn\n   from a local monotone sequence: the differential observable (the sum) depends only on the ids being\n   DISTINCT and STABLE within a run, not their absolute values, so it matches the VM whatever the VM\'s\n   own (process-global) replica sequence happens to be. */\n\ntypedef struct { long long my_rid; long long len, cap; long long *rids; long long *cnts; } logos_crdt;\n\nstatic long long logos_replica_seq = 0;\n\nlogos_crdt *logos_crdt_new(void) {\n    logos_crdt *c = (logos_crdt *)lc_gc_alloc(sizeof(logos_crdt));\n    c->my_rid = logos_replica_seq++;\n    c->len = 1; c->cap = 4;\n    c->rids = (long long *)lc_gc_alloc_atomic((size_t)c->cap * 8);\n    c->cnts = (long long *)lc_gc_alloc_atomic((size_t)c->cap * 8);\n    c->rids[0] = c->my_rid; c->cnts[0] = 0;\n    return c;\n}\n\n/* Increment (or decrement) THIS counter\'s own replica entry, in place. */\nvoid logos_crdt_bump(logos_crdt *c, long long amount, int negate) {\n    long long d = negate ? -amount : amount;\n    for (long long i = 0; i < c->len; i++) {\n        if (c->rids[i] == c->my_rid) { c->cnts[i] += d; return; }\n    }\n    /* my_rid always present (seeded in _new); defensive. */\n    c->cnts[0] += d;\n}\n\nlong long logos_crdt_sum(const logos_crdt *c) {\n    long long s = 0;\n    for (long long i = 0; i < c->len; i++) s += c->cnts[i];\n    return s;\n}\n\nstatic void logos_crdt_put_max(logos_crdt *d, long long rid, long long cnt) {\n    for (long long i = 0; i < d->len; i++) {\n        if (d->rids[i] == rid) { if (cnt > d->cnts[i]) d->cnts[i] = cnt; return; }\n    }\n    if (d->len == d->cap) {\n        d->cap *= 2;\n        d->rids = (long long *)lc_gc_realloc_atomic(d->rids, (size_t)d->cap * 8);\n        d->cnts = (long long *)lc_gc_realloc_atomic(d->cnts, (size_t)d->cap * 8);\n    }\n    d->rids[d->len] = rid; d->cnts[d->len] = cnt; d->len++;\n}\n\n/* Lattice join: per-replica MAX of `s` into `d`, in place (idempotent, commutative, associative). */\nvoid logos_crdt_merge(logos_crdt *d, const logos_crdt *s) {\n    for (long long i = 0; i < s->len; i++) logos_crdt_put_max(d, s->rids[i], s->cnts[i]);\n}\n\n/* `copy` of a counter: the same state, the same replica. */\nlogos_crdt *logos_crdt_clone(const logos_crdt *c) {\n    logos_crdt *d = (logos_crdt *)lc_gc_alloc(sizeof(logos_crdt));\n    *d = *c;\n    d->rids = (long long *)lc_gc_alloc_atomic((size_t)c->cap * 8);\n    d->cnts = (long long *)lc_gc_alloc_atomic((size_t)c->cap * 8);\n    memcpy(d->rids, c->rids, (size_t)c->len * 8);\n    memcpy(d->cnts, c->cnts, (size_t)c->len * 8);\n    return d;\n}\n\n/* ---- Closures \u{2014} a heap `[body_index, captured values\u{2026}, present flags\u{2026}]` cell array ---- */\n\nlong long *logos_closure_new(long long body, long long ncap) {\n    long long *c = (long long *)lc_gc_alloc((size_t)(1 + 2 * ncap) * 8);\n    c[0] = body;\n    return c;\n}\n\nvoid logos_closure_set(long long *c, long long idx, long long val) { c[idx] = val; }\n\n/* ---- `FormatValue` spec helpers (the spec is a compile-time constant, dispatched in codegen) ---- */\n\n/* Currency `$` \u{2014} `${:.2}` (two decimals). Matches `apply_format_spec`\'s float path. */\nchar *logos_fmt_currency(double f) {\n    char *b = (char *)lc_gc_alloc_atomic(64);\n    snprintf(b, 64, \"$%.2f\", f);\n    return b;\n}\n\n/* Precision `.N` \u{2014} `{:.N}` fixed-decimal float (round-to-nearest-even, matching Rust\'s Display). */\nchar *logos_fmt_fixed(double f, int prec) {\n    char *b = (char *)lc_gc_alloc_atomic(64 + (size_t)prec);\n    snprintf(b, 64 + (size_t)prec, \"%.*f\", prec, f);\n    return b;\n}\n\n/* Alignment/width \u{2014} pad `s` to `width` columns: dir \'>\' right, \'<\' left, \'^\' center (extra column on\n   the RIGHT, matching Rust\'s `{:^w}`). No truncation when `s` is already wide enough. */\nchar *logos_pad(const char *s, long long width, char dir) {\n    size_t len = strlen(s);\n    if ((long long)len >= width) return lc_gc_strdup(s);\n    size_t pad = (size_t)width - len;\n    char *out = (char *)lc_gc_alloc_atomic((size_t)width + 1);\n    size_t left = dir == \'>\' ? pad : dir == \'^\' ? pad / 2 : 0;\n    size_t right = pad - left;\n    memset(out, \' \', left);\n    memcpy(out + left, s, len);\n    memset(out + left + len, \' \', right);\n    out[width] = \'\\0\';\n    return out;\n}\n\n/* EXACT i64-vs-f64 comparison for a mixed Int/Float relational op \u{2014} replicates the VM\'s\n * `cmp_i64_f64_exact` + `rel` (crates/logicaffeine_base/src/numeric.rs, semantics/compare.rs). `i`/`f`\n * are the numeric operands (the Int first regardless of source order); `reversed` = 1 when the SOURCE\n * order was (Float, Int) so the comparison is (f vs i); `op` selects lt=0/gt=1/le=2/ge=3/eq=4/ne=5.\n * Returns 0/1. A NaN operand is unordered: every ordering/eq is false, `!=` is true \u{2014} matching `rel`. */\nint logos_cmp_i64_f64_rel(long long i, double f, int reversed, int op) {\n    int ord; /* -2 unordered, else -1 (i<f) / 0 (i==f) / 1 (i>f) */\n    if (isnan(f)) {\n        ord = -2;\n    } else if (isinf(f)) {\n        ord = (f > 0) ? -1 : 1;\n    } else if (i <= (1LL << 53) && i >= -(1LL << 53)) {\n        double di = (double)i;                 /* |i| <= 2^53 is exact */\n        ord = di < f ? -1 : (di > f ? 1 : 0);\n    } else if (f >= 9223372036854775808.0) {   /* f >= 2^63 > any i64 */\n        ord = -1;\n    } else if (f < -9223372036854775808.0) {   /* f < -2^63 < any i64 */\n        ord = 1;\n    } else {\n        long long t = (long long)f;            /* trunc toward zero, exact for f in i64 range */\n        ord = i < t ? -1 : (i > t ? 1 : 0);\n    }\n    if (reversed && ord != -2) ord = -ord;\n    switch (op) {\n        case 0: return ord == -1;              /* lt */\n        case 1: return ord == 1;               /* gt */\n        case 2: return ord == -1 || ord == 0;  /* le  (None -> false) */\n        case 3: return ord == 0 || ord == 1;   /* ge  (None -> false) */\n        case 4: return ord == 0;               /* eq  (None -> false) */\n        default: return ord != 0;              /* ne  (None -> true)  */\n    }\n}\n\n\n/* ---- Seq (heap growable array of uniform 8-byte cells) ----\n * Every scalar element (i64 / f64-bits / char*) is one 8-byte cell; the element KIND is tracked by the\n * emitter and only needed for Show. VALUE SEMANTICS BY OWNERSHIP: `Move` copies the handle (share), and a\n * register\'s collection is mutated only through a `_own` helper handed the register\'s SLOT and its OWNED\n * flag. A clear flag means the handle may be reachable from somewhere else (an alias, a global, a field, an\n * iterator, a closure), so the helper first copies the collection into the slot and sets the flag; then it\n * mutates in place. An alias or an in-flight iterator keeps its own list \u{2014} the VM\'s copy-on-write and\n * snapshot \u{2014} and a register that owns its collection mutates it in amortized O(1). The emitter keeps the\n * flag: an op that makes a fresh collection sets it, any op that could leave the handle elsewhere clears it. */\ntypedef struct { long long len, cap; long long *data; } logos_seq;\n\n/* An empty sequence with room for `capacity` cells, in one block: the cells follow the header until the sequence\n   first outgrows them (`logos_seq_room`). A record, a tuple and an enum value never grow, so each is one block. */\nlogos_seq *logos_seq_new_cap(long long capacity) {\n    if (capacity < 0) capacity = 0;\n    logos_seq *s = (logos_seq *)lc_gc_alloc(sizeof(logos_seq) + (size_t)capacity * 8);\n    s->len = 0;\n    s->cap = capacity;\n    s->data = capacity ? (long long *)(s + 1) : NULL;\n    return s;\n}\n\n/* Room for `cap` cells: cells that still follow the header move to a block of their own, any other block resizes. */\nstatic void logos_seq_room(logos_seq *a, long long cap) {\n    if (a->data == (long long *)(a + 1)) {\n        long long *cells = (long long *)lc_gc_alloc((size_t)cap * 8);\n        memcpy(cells, a->data, (size_t)a->len * 8);\n        a->data = cells;\n    } else {\n        a->data = (long long *)lc_gc_realloc(a->data, (size_t)cap * 8);\n    }\n    a->cap = cap;\n}\n\n/* A fresh sequence, with room for the cells its first pushes add: an enum value\'s tag and payload, a tuple\'s items,\n   a list\'s first items all go in its one block. */\nlogos_seq *logos_seq_new(void) { return logos_seq_new_cap(4); }\n\nstatic logos_seq *logos_seq_dup(const logos_seq *a) {\n    logos_seq *s = logos_seq_new_cap(a->len);\n    s->len = a->len;\n    if (a->len) memcpy(s->data, a->data, (size_t)a->len * 8);\n    return s;\n}\n\n/* In-place append, into a collection its caller has made its own; the header pointer identity stays stable\n   (only the cells move), and growth is taken out of line. */\n__attribute__((noinline)) static void logos_seq_push_growing(logos_seq *a, long long val) {\n    logos_seq_room(a, a->cap ? a->cap * 2 : 4);\n    a->data[a->len++] = val;\n}\n\nvoid logos_seq_push_inplace(logos_seq *a, long long val) {\n    if (__builtin_expect(a->len == a->cap, 0)) {\n        logos_seq_push_growing(a, val);\n        return;\n    }\n    a->data[a->len++] = val;\n}\n\n/* The collection in `*slot`, made the register\'s own: a copy when `*owned` is clear. */\nstatic logos_seq *logos_seq_own(logos_seq **slot, long long *owned) {\n    if (!*owned) { *slot = logos_seq_dup(*slot); *owned = 1; }\n    return *slot;\n}\n\n/* The register\'s own collection, for an op that changes several of its cells in place (`Merge`): the\n   emitter calls it only when the register\'s owned flag is clear. */\nlogos_seq *logos_seq_make_own(logos_seq **slot, long long *owned) {\n    return logos_seq_own(slot, owned);\n}\n\n__attribute__((noinline)) static void logos_seq_push_copying(logos_seq **slot, long long *owned, long long val) {\n    logos_seq_push_inplace(logos_seq_own(slot, owned), val);\n}\n\n/* `Push val to xs`. `val` arrives by value, read before the register is made its own. */\nvoid logos_seq_push_own(logos_seq **slot, long long *owned, long long val) {\n    if (__builtin_expect(!*owned, 0)) {\n        logos_seq_push_copying(slot, owned, val);\n        return;\n    }\n    logos_seq_push_inplace(*slot, val);\n}\n\n/* `args()` \u{2192} a `Seq of Text` of the process argv (index 1 is the program name, exactly as the VM\'s\n   `program_args`), so `item 2 of args()` is the first real argument. */\nlogos_seq *logos_args(void) {\n    logos_seq *s = logos_seq_new();\n    for (int i = 0; i < logos_argc; i++) logos_seq_push_inplace(s, (long long)logos_argv[i]);\n    return s;\n}\n\nlong long logos_seq_len(const logos_seq *a) { return a->len; }\n\n/* `Pop from xs into v` \u{2014} the last element, removed (`present` 1), or `nothing` from an empty list (`present`\n   0). An empty pop changes nothing, so it leaves the register\'s ownership as it found it. */\n/* The call sites whose callee stops the program itself rather than answer nothing: pairs of a return\n   address and the sentence to stop with, ended by a zero pair. The emitter writes the table; a helper\n   searches it only on its way to stopping. */\nextern const struct { const void *site; const char *reason; } logos_fail_sites[];\n\n__attribute__((noreturn, noinline)) static void logos_fail_at(const void *site) {\n    for (long long i = 0; logos_fail_sites[i].site; i++) {\n        if (logos_fail_sites[i].site == site) logos_fatal(logos_fail_sites[i].reason);\n    }\n    abort();\n}\n\ntypedef struct { long long present, value; } logos_popped;\nlogos_popped logos_seq_pop_own(logos_seq **slot, long long *owned) {\n    logos_popped r = {0, 0};\n    if (!(*slot)->len) return r;\n    logos_seq *s = logos_seq_own(slot, owned);\n    r.present = 1;\n    r.value = s->data[--s->len];\n    return r;\n}\n\n/* `Pop from xs into v` where the op after it fails on `nothing`: the last element, or, from an empty list,\n   the program stopped with the sentence registered for the call site. */\n__attribute__((noinline)) long long logos_seq_pop_value(logos_seq **slot, long long *owned) {\n    if (!(*slot)->len) logos_fail_at(__builtin_return_address(0));\n    logos_seq *s = logos_seq_own(slot, owned);\n    return s->data[--s->len];\n}\n\n/* In-place indexed write (1-based) \u{2014} a struct-field mutation that must be visible through every alias\n   of the struct (`CrdtBump`\'s counter update; the seq header pointer stays stable). */\n__attribute__((noinline, cold)) static void logos_seq_set_from_back(logos_seq *a, long long i, long long val) {\n    a->data[logos_index_from_back(i, a->len)] = val;\n}\n\nvoid logos_seq_set_inplace(logos_seq *a, long long i, long long val) {\n    if (__builtin_expect(i < 1 || i > a->len, 0)) {\n        logos_seq_set_from_back(a, i, val);\n        return;\n    }\n    a->data[i - 1] = val;\n}\n\n/* `Set item i of xs to val` (1-based, or from the back when negative), and a struct\'s field write (its cells\n   are a seq). An index out of range stops the program as the VM does, before anything is copied. */\n__attribute__((noinline)) static void logos_seq_set_own_copying(logos_seq **slot, long long *owned, long long i, long long val) {\n    long long at = logos_resolve_index(i, (*slot)->len);\n    logos_seq_own(slot, owned)->data[at] = val;\n}\n\nvoid logos_seq_set_own(logos_seq **slot, long long *owned, long long i, long long val) {\n    logos_seq *s = *slot;\n    if (__builtin_expect(*owned && i >= 1 && i <= s->len, 1)) {\n        s->data[i - 1] = val;\n        return;\n    }\n    logos_seq_set_own_copying(slot, owned, i, val);\n}\n\n/* The value in field `cell` (1-based) of the record in `*slot`, made the register\'s own record\'s own: the record\n   copied unless `*owned` says the register is its only holder, the value copied with `copy` unless\n   `*field_owned` says the record is its only holder, and both flags set. */\n__attribute__((noinline)) static long long logos_field_own(logos_seq **slot, long long *owned, long long *field_owned,\n    long long cell, long long (*copy)(long long)) {\n    logos_seq *record = logos_seq_own(slot, owned);\n    long long value = record->data[cell - 1];\n    if (!*field_owned) {\n        value = copy(value);\n        record->data[cell - 1] = value;\n        *field_owned = 1;\n    }\n    return value;\n}\n\nstatic long long logos_field_seq_copy(long long list) { return (long long)logos_seq_dup((const logos_seq *)list); }\n\n__attribute__((noinline)) static void logos_field_push_copying(logos_seq **slot, long long *owned, long long *field_owned,\n    long long cell, long long val) {\n    logos_seq_push_inplace((logos_seq *)logos_field_own(slot, owned, field_owned, cell, logos_field_seq_copy), val);\n}\n\n/* `Push val to r\'s field` \u{2014} into the register\'s own record\'s own list: in place while the field flag is set\n   (the emitter keeps a field flag set only while its register\'s owned flag is), so a loop of pushes copies at\n   most once. */\nvoid logos_field_push_own(logos_seq **slot, long long *owned, long long *field_owned, long long cell, long long val) {\n    if (__builtin_expect(!*field_owned, 0)) {\n        logos_field_push_copying(slot, owned, field_owned, cell, val);\n        return;\n    }\n    logos_seq_push_inplace((logos_seq *)(*slot)->data[cell - 1], val);\n}\n\nstatic long long logos_field_crdt_copy(long long c) { return (long long)logos_crdt_clone((const logos_crdt *)c); }\n\n__attribute__((noinline)) static void logos_field_bump_copying(logos_seq **slot, long long *owned, long long *field_owned,\n    long long cell, long long amount, int negate) {\n    logos_crdt_bump((logos_crdt *)logos_field_own(slot, owned, field_owned, cell, logos_field_crdt_copy), amount, negate);\n}\n\n/* `Increase/Decrease r\'s counter by amount` \u{2014} the register\'s own record\'s own counter: in place while the\n   field flag is set. */\nvoid logos_field_bump_own(logos_seq **slot, long long *owned, long long *field_owned, long long cell, long long amount,\n    int negate) {\n    if (__builtin_expect(!*field_owned, 0)) {\n        logos_field_bump_copying(slot, owned, field_owned, cell, amount, negate);\n        return;\n    }\n    logos_crdt_bump((logos_crdt *)(*slot)->data[cell - 1], amount, negate);\n}\n\n/* `a followed by b` \u{2014} fresh seq with a\'s elements then b\'s. */\nlogos_seq *logos_seq_concat(const logos_seq *a, const logos_seq *b) {\n    logos_seq *s = logos_seq_new_cap(a->len + b->len);\n    s->len = a->len + b->len;\n    if (a->len) memcpy(s->data, a->data, (size_t)a->len * 8);\n    if (b->len) memcpy(s->data + a->len, b->data, (size_t)b->len * 8);\n    return s;\n}\n\n/* `items start through end of a` \u{2014} the VM\'s `slice`: the 1-based inclusive range, and empty unless it lies\n   within the list (`slice.get(start - 1 .. end)`, the bounds read as unsigned). */\nlogos_seq *logos_seq_slice(const logos_seq *a, long long start, long long end) {\n    unsigned long long from = (unsigned long long)start ? (unsigned long long)start - 1 : 0, to = (unsigned long long)end;\n    logos_seq *s = logos_seq_new();\n    if (from < to && to <= (unsigned long long)a->len) {\n        for (unsigned long long i = from; i < to; i++) logos_seq_push_inplace(s, a->data[i]);\n    }\n    return s;\n}\n\n/* Element equality by kind (0=Int, 1=Float, 3=Text) \u{2014} the VM\'s `values_equal` for scalar cells. */\nstatic int logos_cell_eq(long long a, long long b, int kind) {\n    if (kind == 3) return strcmp((const char *)a, (const char *)b) == 0;\n    if (kind == 1) { double x, y; memcpy(&x, &a, 8); memcpy(&y, &b, 8); return x == y; }\n    return a == b;\n}\n\n/* Two struct fields compared by kind (a policy `ObjectFieldEquals` \u{2014} the VM\'s `values_equal`). The\n   cells are 1-based; struct field indices are always in range. */\nint logos_struct_field_eq(logos_seq *a, long long ai, logos_seq *b, long long bi, int kind) {\n    return logos_cell_eq(a->data[ai - 1], b->data[bi - 1], kind);\n}\n\n/* `a contains val` \u{2014} membership by element kind. */\nint logos_seq_contains(const logos_seq *a, long long val, int kind) {\n    for (long long i = 0; i < a->len; i++) {\n        if (logos_cell_eq(a->data[i], val, kind)) return 1;\n    }\n    return 0;\n}\n\n/* `a contains val` where the items or the needle are rationals (`items_rational`, `val_rational`): by value, an Int\n   by the rational it equals. */\nint logos_seq_contains_exact(const logos_seq *a, int items_rational, long long val, int val_rational) {\n    for (long long i = 0; i < a->len; i++) {\n        if (logos_ldec_cmp(a->data[i], items_rational, val, val_rational) == 0) return 1;\n    }\n    return 0;\n}\n\n/* An Int put among rationals goes in as the rational it equals: a literal\'s item, a pushed one, one stored. */\nvoid logos_seq_push_inplace_ldec(logos_seq *a, long long v) { logos_seq_push_inplace(a, logos_ldec_of_int(v)); }\nvoid logos_seq_push_own_ldec(logos_seq **slot, long long *owned, long long v) {\n    logos_seq_push_own(slot, owned, logos_ldec_of_int(v));\n}\nvoid logos_seq_set_own_ldec(logos_seq **slot, long long *owned, long long i, long long v) {\n    logos_seq_set_own(slot, owned, i, logos_ldec_of_int(v));\n}\n\n/* A list of Ints as the list of the rationals they equal. */\nlogos_seq *logos_seq_as_ldec(const logos_seq *a) {\n    logos_seq *s = logos_seq_new();\n    for (long long i = 0; i < a->len; i++) logos_seq_push_inplace_ldec(s, a->data[i]);\n    return s;\n}\n\n/* ---- Set (insertion-ordered, dedup\'d \u{2014} shares the logos_seq storage) ---- */\n\n/* `Add val to s` \u{2014} append if not already present (dedup). A present element changes nothing. */\nvoid logos_set_add_own(logos_seq **slot, long long *owned, long long val, int kind) {\n    if (logos_seq_contains(*slot, val, kind)) return;\n    logos_seq_push_inplace(logos_seq_own(slot, owned), val);\n}\n\n/* `Remove val from s` \u{2014} drop every matching element, keeping the order of the rest. An absent element\n   changes nothing. */\nvoid logos_set_remove_own(logos_seq **slot, long long *owned, long long val, int kind) {\n    if (!logos_seq_contains(*slot, val, kind)) return;\n    logos_seq *s = logos_seq_own(slot, owned);\n    long long kept = 0;\n    for (long long i = 0; i < s->len; i++) {\n        if (!logos_cell_eq(s->data[i], val, kind)) s->data[kept++] = s->data[i];\n    }\n    s->len = kept;\n}\n\n/* `a union b` \u{2014} a\'s elements, then b\'s novel elements (insertion-ordered). */\nlogos_seq *logos_set_union(const logos_seq *a, const logos_seq *b, int kind) {\n    logos_seq *s = logos_seq_dup(a);\n    for (long long i = 0; i < b->len; i++) {\n        if (!logos_seq_contains(s, b->data[i], kind)) {\n            if (s->len == s->cap) logos_seq_room(s, s->cap ? s->cap * 2 : 4);\n            s->data[s->len++] = b->data[i];\n        }\n    }\n    return s;\n}\n\n/* `a intersect b` \u{2014} a\'s elements that are also in b (a\'s order). */\nlogos_seq *logos_set_intersect(const logos_seq *a, const logos_seq *b, int kind) {\n    logos_seq *s = logos_seq_new();\n    for (long long i = 0; i < a->len; i++) {\n        if (logos_seq_contains(b, a->data[i], kind)) {\n            if (s->len == s->cap) logos_seq_room(s, s->cap ? s->cap * 2 : 4);\n            s->data[s->len++] = a->data[i];\n        }\n    }\n    return s;\n}\n\n/* `Show` of a set \u{2014} `{1, 2, 3}` (braces; insertion order; text elements unquoted). */\nvoid logos_set_show_int(const logos_seq *a) {\n    putchar(\'{\');\n    for (long long i = 0; i < a->len; i++) { if (i) fputs(\", \", stdout); printf(\"%lld\", a->data[i]); }\n    fputs(\"}\\n\", stdout);\n}\nvoid logos_set_show_text(const logos_seq *a) {\n    putchar(\'{\');\n    for (long long i = 0; i < a->len; i++) { if (i) fputs(\", \", stdout); fputs((const char *)a->data[i], stdout); }\n    fputs(\"}\\n\", stdout);\n}\n\n/* `copy of a` \u{2014} deep clone. */\nlogos_seq *logos_seq_clone(const logos_seq *a) { return logos_seq_dup(a); }\n\n/* A struct is a fixed array of `n` field cells (declaration order), zero-initialized. */\nlogos_seq *logos_struct_new(long long n) {\n    logos_seq *s = logos_seq_new_cap(n);\n    if (n > 0) memset(s->data, 0, (size_t)n * 8);\n    s->len = n > 0 ? n : 0;\n    return s;\n}\n\n/* Print without a trailing newline (for building `Name { f: v, ... }` piece by piece). */\nvoid logos_print_raw(const char *s) { fputs(s, stdout); }\nvoid logos_print_nl(void) { putchar(\'\\n\'); }\n\n/* Granlund\u{2013}Montgomery / libdivide unsigned magic division \u{2014} a byte-for-byte port of the VM\'s\n * `magic_eval` (vm/compiler.rs). Emitted only for a constant non-power-of-two divisor with an\n * Oracle-proven non-negative dividend; `mul_back == 0` is `/`, `mul_back == c` is `%`. */\nlong long logos_magic_div(long long x, unsigned long long magic, int more, long long mul_back) {\n    unsigned long long n = (unsigned long long)x;\n    unsigned long long q;\n    if (more & 0x80) {\n        q = n >> (more & 0x3F);\n    } else {\n        unsigned long long hi = (unsigned long long)(((unsigned __int128)magic * (unsigned __int128)n) >> 64);\n        if (more & 0x40) {\n            unsigned long long t = ((n - hi) >> 1) + hi;\n            q = t >> (more & 0x3F);\n        } else {\n            q = hi >> (more & 0x3F);\n        }\n    }\n    if (mul_back == 0) return (long long)q;\n    return x - (long long)q * mul_back;\n}\n\n/* Integer exponentiation by squaring (wrapping, matching the VM\'s in-i64 result). A negative exponent, or\n * one past 32 bits, stops the program with the VM\'s sentence. */\nlong long logos_ipow(long long base, long long exp) {\n    if (exp < 0) logos_fatal(logos_negative_exponent_refusal);\n    if (exp > 4294967295LL) logos_fatal(logos_exponent_too_large_refusal);\n    unsigned long long r = 1, b = (unsigned long long)base, e = (unsigned long long)exp;\n    while (e > 0) { if (e & 1) r *= b; b *= b; e >>= 1; }\n    return (long long)r;\n}\n\n/* `lo to hi` \u{2014} a materialized inclusive integer range (empty if lo > hi). */\nlogos_seq *logos_seq_range(long long lo, long long hi) {\n    logos_seq *s = logos_seq_new();\n    for (long long v = lo; v <= hi; v++) {\n        if (s->len == s->cap) logos_seq_room(s, s->cap ? s->cap * 2 : 8);\n        s->data[s->len++] = v;\n    }\n    return s;\n}\n\n/* `start to end`, and `items start through end of a`, with a bound that is a rational (`lf`, `hf`): each the\n   integer a whole one is, a fraction or one past i64 refused in the VM\'s words for the place. */\nlogos_seq *logos_seq_range_ldec(long long lo, int lf, long long hi, int hf, const char *past_word, const char *fraction) {\n    return logos_seq_range(lf ? logos_ldec_as_i64(lo, past_word, fraction) : lo,\n                           hf ? logos_ldec_as_i64(hi, past_word, fraction) : hi);\n}\nlogos_seq *logos_seq_slice_ldec(const logos_seq *a, long long start, int sf, long long end, int ef,\n                                const char *past_word, const char *fraction) {\n    return logos_seq_slice(a, sf ? logos_ldec_as_i64(start, past_word, fraction) : start,\n                           ef ? logos_ldec_as_i64(end, past_word, fraction) : end);\n}\n\n/* `item i of xs` \u{2014} 1-based, or from the back when negative; an index out of range stops the program as the\n   VM does. */\n__attribute__((noinline, cold)) static long long logos_seq_index_from_back(const logos_seq *a, long long i) {\n    return a->data[logos_index_from_back(i, a->len)];\n}\n\nlong long logos_seq_index(const logos_seq *a, long long i) {\n    if (__builtin_expect(i < 1 || i > a->len, 0)) return logos_seq_index_from_back(a, i);\n    return a->data[i - 1];\n}\n\n/* `length of text` \u{2014} BYTE length (the VM\'s `Text` length is `s.len()`, not the char count). */\nlong long logos_text_len(const char *s) { return (long long)strlen(s); }\n\n/* `item i of text` \u{2014} 1-based character access returning a single-character Text, matching the VM\'s\n   `index_get`: an ASCII string indexes by byte; otherwise the i-th Unicode scalar (negative i counts\n   from the end); an out-of-range index errors like the VM (exit nonzero). */\nchar *logos_text_index(const char *s, long long i) {\n    long long blen = (long long)strlen(s);\n    int ascii = 1;\n    for (long long k = 0; k < blen; k++) {\n        if ((unsigned char)s[k] >= 0x80) { ascii = 0; break; }\n    }\n    if (ascii && i >= 1 && i <= blen) {\n        char *out = (char *)lc_gc_alloc_atomic(2);\n        out[0] = s[i - 1];\n        out[1] = \'\\0\';\n        return out;\n    }\n    long long char_len = blen;\n    if (!ascii) {\n        char_len = 0;\n        for (long long k = 0; k < blen;) {\n            unsigned char c = (unsigned char)s[k];\n            int n = c < 0x80 ? 1 : c < 0xE0 ? 2 : c < 0xF0 ? 3 : 4;\n            k += n;\n            char_len++;\n        }\n    }\n    long long idx;\n    if (i >= 1) {\n        idx = i - 1;\n        if (idx >= char_len) goto oob;\n    } else if (i <= -1) {\n        long long back = -i;\n        if (back > char_len) goto oob;\n        idx = char_len - back;\n    } else {\n        goto oob;\n    }\n    {\n        long long k = 0, ci = 0;\n        while (k < blen) {\n            unsigned char c = (unsigned char)s[k];\n            int n = c < 0x80 ? 1 : c < 0xE0 ? 2 : c < 0xF0 ? 3 : 4;\n            if (ci == idx) {\n                char *out = (char *)lc_gc_alloc_atomic(n + 1);\n                for (int t = 0; t < n; t++) out[t] = s[k + t];\n                out[n] = \'\\0\';\n                return out;\n            }\n            k += n;\n            ci++;\n        }\n    }\noob:\n    logos_fatalf(logos_index_refusal, i);\n}\n\n/* ---- Files: the VM\'s sandboxed in-memory VFS, which keeps files only inside a `## Test`\'s sealed world ----\n   A program keeps none, so every read finds nothing and stops the program with `missing` (a format of the\n   path) \u{2014} the VM\'s sentence, taken from the VM by the emitter. */\n__attribute__((noreturn)) void logos_vfs_read(const char *path, const char *missing) {\n    size_t n = strlen(missing) + strlen(path) + 1;\n    char *why = (char *)lc_gc_alloc_atomic(n);\n    snprintf(why, n, missing, path);\n    logos_fatal(why);\n}\n\n/* `Repeat for c in t` \u{2014} the Text\'s characters, each a Text of its own. */\nlogos_seq *logos_text_chars(const char *s) {\n    logos_seq *out = logos_seq_new();\n    const unsigned char *p = (const unsigned char *)s;\n    while (*p) {\n        unsigned cp;\n        int n = logos_utf8_at(p, &cp);\n        char *c = (char *)lc_gc_alloc_atomic((size_t)n + 1);\n        memcpy(c, p, (size_t)n);\n        c[n] = \'\\0\';\n        logos_seq_push_inplace(out, (long long)c);\n        p += n;\n    }\n    return out;\n}\n\n/* Eight bytes from the system\'s entropy; `getentropy` fails only for a request over 256 bytes. */\nstatic unsigned long long logos_entropy(void) {\n    unsigned long long draw;\n    if (getentropy(&draw, sizeof draw) != 0) abort();\n    return draw;\n}\n\n/* `randomInt(lo, hi)` \u{2014} uniform over `lo..=hi` from the system\'s entropy (rejection sampling, so no bound is\n   favored); crossed bounds stop the program with `logos_random_bounds_refusal`. */\nlong long logos_random_int(long long lo, long long hi) {\n    if (lo > hi) {\n        char why[256];\n        snprintf(why, sizeof why, logos_random_bounds_refusal, lo, hi);\n        logos_fatal(lc_gc_strdup(why));\n    }\n    unsigned long long span = (unsigned long long)hi - (unsigned long long)lo, draw, limit;\n    if (span == ~0ULL) return (long long)logos_entropy();\n    limit = ~0ULL - (~0ULL % (span + 1) + 1) % (span + 1);\n    do draw = logos_entropy(); while (draw > limit);\n    return (long long)((unsigned long long)lo + draw % (span + 1));\n}\n\n/* `text_bytes(t)` \u{2014} each UTF-8 byte of the Text, as an Int 0..255. */\nlogos_seq *logos_text_bytes(const char *s) {\n    logos_seq *out = logos_seq_new();\n    for (const unsigned char *p = (const unsigned char *)s; *p; p++) logos_seq_push_inplace(out, *p);\n    return out;\n}\n\n/* `readReals(path)` \u{2014} the file\'s little-endian binary64 values, eight bytes a value in order, each slot of the\n   Seq of Real the value\'s bits; refused as `logicaffeine_system::file::read_reals` refuses: a file it cannot read,\n   or one that is not a whole number of values. */\nlogos_seq *logos_read_reals(const char *path) {\n    FILE *f = fopen(path, \"rb\");\n    char *why;\n    size_t n;\n    if (!f) {\n        const char *reason = strerror(errno);\n        n = strlen(path) + strlen(reason) + 64;\n        why = (char *)lc_gc_alloc_atomic(n);\n        snprintf(why, n, \"readReals: cannot read \'%s\': %s\", path, reason);\n        logos_fatal(why);\n    }\n    fseek(f, 0, SEEK_END);\n    long size = ftell(f);\n    fseek(f, 0, SEEK_SET);\n    if (size < 0 || size % 8 != 0) {\n        fclose(f);\n        n = strlen(path) + 96;\n        why = (char *)lc_gc_alloc_atomic(n);\n        snprintf(why, n, \"readReals: \'%s\' holds %ld bytes, not a whole number of 8-byte Reals\", path, size);\n        logos_fatal(why);\n    }\n    logos_seq *out = logos_seq_new_cap(size / 8 > 0 ? size / 8 : 1);\n    unsigned char b[8];\n    for (long i = 0; i < size / 8; i++) {\n        if (fread(b, 1, 8, f) != 8) logos_fatals(\"readReals: cannot read \'%s\'\", path);\n        unsigned long long bits = 0;\n        for (int k = 7; k >= 0; k--) bits = (bits << 8) | b[k];\n        logos_seq_push_inplace(out, (long long)bits);\n    }\n    fclose(f);\n    return out;\n}\n\n/* The length a UTF-8 sequence led by `b` claims, 0 for a byte no sequence starts with \u{2014} Rust\'s\n   `utf8_char_width`. */\nstatic int logos_utf8_width(unsigned b) {\n    if (b < 0x80) return 1;\n    if (b < 0xC2) return 0;\n    if (b < 0xE0) return 2;\n    if (b < 0xF0) return 3;\n    if (b < 0xF5) return 4;\n    return 0;\n}\n\n/* Rust\'s UTF-8 validation (`core::str::from_utf8`), step for step: 1 when `v[0..n)` is UTF-8, else 0 with\n   where the valid prefix ends and the length of the invalid sequence there \u{2014} 0 when the bytes end inside a\n   sequence \u{2014} the two facts `Utf8Error` reports. */\nstatic int logos_utf8_valid(const unsigned char *v, long long n, long long *valid_up_to, int *error_len) {\n    long long i = 0;\n    while (i < n) {\n        long long start = i;\n        unsigned first = v[i], b;\n#define LOGOS_UTF8_FAIL(len) do { *valid_up_to = start; *error_len = (len); return 0; } while (0)\n#define LOGOS_UTF8_NEXT() do { if (++i >= n) LOGOS_UTF8_FAIL(0); b = v[i]; } while (0)\n#define LOGOS_UTF8_CONT(len) do { LOGOS_UTF8_NEXT(); if (b < 0x80 || b >= 0xC0) LOGOS_UTF8_FAIL(len); } while (0)\n        if (first >= 0x80) {\n            switch (logos_utf8_width(first)) {\n            case 2:\n                LOGOS_UTF8_CONT(1);\n                break;\n            case 3:\n                LOGOS_UTF8_NEXT();\n                if (!((first == 0xE0 && b >= 0xA0 && b <= 0xBF) || (first >= 0xE1 && first <= 0xEC && b >= 0x80 && b <= 0xBF)\n                      || (first == 0xED && b >= 0x80 && b <= 0x9F) || (first >= 0xEE && b >= 0x80 && b <= 0xBF)))\n                    LOGOS_UTF8_FAIL(1);\n                LOGOS_UTF8_CONT(2);\n                break;\n            case 4:\n                LOGOS_UTF8_NEXT();\n                if (!((first == 0xF0 && b >= 0x90 && b <= 0xBF) || (first >= 0xF1 && first <= 0xF3 && b >= 0x80 && b <= 0xBF)\n                      || (first == 0xF4 && b >= 0x80 && b <= 0x8F)))\n                    LOGOS_UTF8_FAIL(1);\n                LOGOS_UTF8_CONT(2);\n                LOGOS_UTF8_CONT(3);\n                break;\n            default:\n                LOGOS_UTF8_FAIL(1);\n            }\n        }\n#undef LOGOS_UTF8_CONT\n#undef LOGOS_UTF8_NEXT\n#undef LOGOS_UTF8_FAIL\n        i++;\n    }\n    return 1;\n}\n\n/* `text_from_bytes(bytes)` \u{2014} the low byte of each element, as a Text when they are UTF-8. Otherwise the\n   program stops with `logos_utf8_invalid_refusal` (of the invalid sequence\'s length and where it starts) or\n   `logos_utf8_incomplete_refusal` (of where the unfinished sequence starts). */\nchar *logos_text_from_bytes(const logos_seq *b) {\n    unsigned char *bytes = (unsigned char *)lc_gc_alloc_atomic((size_t)b->len + 1);\n    for (long long i = 0; i < b->len; i++) bytes[i] = (unsigned char)(b->data[i] & 0xff);\n    bytes[b->len] = \'\\0\';\n    long long at;\n    int len;\n    if (!logos_utf8_valid(bytes, b->len, &at, &len)) {\n        char why[512];\n        if (len) snprintf(why, sizeof why, logos_utf8_invalid_refusal, len, at);\n        else snprintf(why, sizeof why, logos_utf8_incomplete_refusal, at);\n        logos_fatal(lc_gc_strdup(why));\n    }\n    return (char *)bytes;\n}\n\nvoid logos_seq_show_int(const logos_seq *a) {\n    putchar(\'[\');\n    for (long long i = 0; i < a->len; i++) { if (i) fputs(\", \", stdout); printf(\"%lld\", a->data[i]); }\n    fputs(\"]\\n\", stdout);\n}\n\nvoid logos_seq_show_bool(const logos_seq *a) {\n    putchar(\'[\');\n    for (long long i = 0; i < a->len; i++) { if (i) fputs(\", \", stdout); fputs(a->data[i] ? \"true\" : \"false\", stdout); }\n    fputs(\"]\\n\", stdout);\n}\n\nvoid logos_seq_show_float(const logos_seq *a) {\n    putchar(\'[\');\n    for (long long i = 0; i < a->len; i++) {\n        if (i) fputs(\", \", stdout);\n        double f; memcpy(&f, &a->data[i], 8);\n        char *s = logos_fmt_f64(f); fputs(s, stdout); lc_gc_free(s);\n    }\n    fputs(\"]\\n\", stdout);\n}\n\n/* Text elements render UNQUOTED inside a list, like the VM\'s `[foo, bar]`. */\nvoid logos_seq_show_text(const logos_seq *a) {\n    putchar(\'[\');\n    for (long long i = 0; i < a->len; i++) { if (i) fputs(\", \", stdout); fputs((const char *)a->data[i], stdout); }\n    fputs(\"]\\n\", stdout);\n}\n\n/* ---- Map (insertion-ordered key\u{2192}value; parallel key/value arrays of uniform 8-byte cells) ---- */\ntypedef struct { long long len, cap; long long *keys; long long *vals; } logos_map;\n\nlogos_map *logos_map_new(void) {\n    logos_map *m = (logos_map *)lc_gc_alloc(sizeof(logos_map));\n    m->len = 0; m->cap = 0; m->keys = NULL; m->vals = NULL;\n    return m;\n}\n\nlogos_map *logos_map_new_cap(long long capacity) {\n    if (capacity < 0) capacity = 0;\n    logos_map *m = (logos_map *)lc_gc_alloc(sizeof(logos_map));\n    m->len = 0; m->cap = capacity;\n    m->keys = capacity ? (long long *)lc_gc_alloc((size_t)capacity * 8) : NULL;\n    m->vals = capacity ? (long long *)lc_gc_alloc((size_t)capacity * 8) : NULL;\n    return m;\n}\n\nstatic logos_map *logos_map_dup(const logos_map *a) {\n    logos_map *m = (logos_map *)lc_gc_alloc(sizeof(logos_map));\n    m->len = a->len; m->cap = a->len;\n    m->keys = a->len ? (long long *)lc_gc_alloc((size_t)a->len * 8) : NULL;\n    m->vals = a->len ? (long long *)lc_gc_alloc((size_t)a->len * 8) : NULL;\n    if (a->len) { memcpy(m->keys, a->keys, (size_t)a->len * 8); memcpy(m->vals, a->vals, (size_t)a->len * 8); }\n    return m;\n}\n\n/* `Set item key of m to val` \u{2014} insert or update (insertion-ordered), in the register\'s own map (a copy\n   when its owned flag is clear; see the Seq section). `key_kind` selects key compare. */\nvoid logos_map_set_own(logos_map **slot, long long *owned, long long key, long long val, int key_kind) {\n    if (!*owned) { *slot = logos_map_dup(*slot); *owned = 1; }\n    logos_map *m = *slot;\n    for (long long i = 0; i < m->len; i++) {\n        if (logos_cell_eq(m->keys[i], key, key_kind)) { m->vals[i] = val; return; }\n    }\n    if (m->len == m->cap) {\n        m->cap = m->cap ? m->cap * 2 : 4;\n        m->keys = (long long *)lc_gc_realloc(m->keys, (size_t)m->cap * 8);\n        m->vals = (long long *)lc_gc_realloc(m->vals, (size_t)m->cap * 8);\n    }\n    m->keys[m->len] = key; m->vals[m->len] = val; m->len++;\n}\n\n/* The key-wise merge of two maps (the VM\'s `crdt_merge_field` on maps): `a`\'s entries in its order, each key\n   `b` also holds taking the merge of the two values \u{2014} Ints summed (`value_rule` 0) or `b`\'s value (1) \u{2014} then\n   `b`\'s other keys in its order. A fresh map. */\nlogos_map *logos_map_merge(const logos_map *a, const logos_map *b, int key_kind, int value_rule) {\n    logos_map *out = logos_map_dup(a);\n    for (long long i = 0; i < b->len; i++) {\n        long long j = 0;\n        while (j < out->len && !logos_cell_eq(out->keys[j], b->keys[i], key_kind)) j++;\n        if (j < out->len) {\n            out->vals[j] = value_rule == 0\n                ? (long long)((unsigned long long)out->vals[j] + (unsigned long long)b->vals[i])\n                : b->vals[i];\n            continue;\n        }\n        if (out->len == out->cap) {\n            out->cap = out->cap ? out->cap * 2 : 4;\n            out->keys = (long long *)lc_gc_realloc(out->keys, (size_t)out->cap * 8);\n            out->vals = (long long *)lc_gc_realloc(out->vals, (size_t)out->cap * 8);\n        }\n        out->keys[out->len] = b->keys[i];\n        out->vals[out->len] = b->vals[i];\n        out->len++;\n    }\n    return out;\n}\n\n/* `Merge`/`Converge` of cell `cell` (1-based) of two records of one type, for the fields the emitter does\n   not merge inline: what the VM\'s `crdt_merge_field` makes of the target\'s value and the source\'s, by the\n   emitter\'s rule \u{2014} 3 a fresh counter holding the per-replica maximum, 4 the union of sets of element kind\n   `a`, 5 the key-wise merge of maps keyed by kind `a` under value rule `b`. */\nlong long logos_merge_cell(const logos_seq *target, const logos_seq *source, long long cell, int how, int a, int b) {\n    long long mine = target->data[cell - 1], theirs = source->data[cell - 1];\n    switch (how) {\n        case 3: {\n            logos_crdt *merged = logos_crdt_clone((const logos_crdt *)mine);\n            logos_crdt_merge(merged, (const logos_crdt *)theirs);\n            return (long long)merged;\n        }\n        case 4: return (long long)logos_set_union((const logos_seq *)mine, (const logos_seq *)theirs, a);\n        case 5: return (long long)logos_map_merge((const logos_map *)mine, (const logos_map *)theirs, a, b);\n        default: abort();\n    }\n}\n\n/* `item key of m` \u{2014} lookup; a missing key stops the program with the VM\'s sentence, naming the key. */\nlong long logos_map_get(const logos_map *a, long long key, int key_kind) {\n    for (long long i = 0; i < a->len; i++) {\n        if (logos_cell_eq(a->keys[i], key, key_kind)) return a->vals[i];\n    }\n    char *shown = logos_val_to_str(key, key_kind);\n    size_t n = strlen(logos_missing_key_refusal) + strlen(shown) + 1;\n    char *why = (char *)lc_gc_alloc_atomic(n);\n    snprintf(why, n, logos_missing_key_refusal, shown);\n    logos_fatal(why);\n}\n\n/* `length of map` \u{2014} the entry count. */\nlong long logos_map_len(const logos_map *a) { return a->len; }\n\n/* `map contains key` \u{2014} key membership (never errors on a missing key), matching the VM\'s `Contains`. */\nlong long logos_map_has(const logos_map *a, long long key, int key_kind) {\n    for (long long i = 0; i < a->len; i++) {\n        if (logos_cell_eq(a->keys[i], key, key_kind)) return 1;\n    }\n    return 0;\n}\n\n/* `Repeat for (k, v) in m` \u{2014} the map\'s entries in order, each a `(key, value)` tuple. */\nlogos_seq *logos_map_pairs(const logos_map *m) {\n    logos_seq *out = logos_seq_new();\n    for (long long i = 0; i < m->len; i++) {\n        logos_seq *pair = logos_seq_new();\n        logos_seq_push_inplace(pair, m->keys[i]);\n        logos_seq_push_inplace(pair, m->vals[i]);\n        logos_seq_push_inplace(out, (long long)pair);\n    }\n    return out;\n}\n\n/* `Show` of a map \u{2014} `{k: v, ...}` (insertion order; keys/values formatted by kind, text unquoted). */\nvoid logos_map_show(const logos_map *a, int key_kind, int val_kind) {\n    putchar(\'{\');\n    for (long long i = 0; i < a->len; i++) {\n        if (i) fputs(\", \", stdout);\n        char *k = logos_val_to_str(a->keys[i], key_kind);\n        char *v = logos_val_to_str(a->vals[i], val_kind);\n        printf(\"%s: %s\", k, v);\n        lc_gc_free(k); lc_gc_free(v);\n    }\n    fputs(\"}\\n\", stdout);\n}\n\n/* ---- Deep copy and structural equality \u{2014} the VM\'s `deep_clone` and `values_equal`, by the shape the emitter\n   gives each kind. A shape is `[form, n, parts]`: forms 0 (Int), 7 (Text), 8 (Float) and 9 (Rational)\n   are copied as values; 1 is a sequence with one element shape; 10 a set; 2 a map (key and value shapes);\n   3 a declared enum with tagged constructor payload shapes; 6 a counter. */\n/* Forms 11 (tuple) and 12 (record) use the sequence layout without collection identity.\n   Forms 13/14 are Option/Result constructors. Forms 16..20 distinguish Bool, Date, Moment,\n   Word32 and opaque identities from Int; 21 is a peer; 22 a cell of the exact extension; 23 `nothing`; 24 a span,\n   its months and days packed into one word. */\ntypedef struct { long long form, n; const void *const *parts; } logos_shape;\ntypedef struct { long long tag, n; const logos_shape *const *parts; } logos_variant;\n\n/* Form 22 is a cell of the exact extension, which the extension\'s adapter copies and compares (two values of which\n   one is a cell, each by its own shape), set when the shim embeds it. */\nstatic long long (*logos_tower_copy_hook)(long long);\nstatic int (*logos_tower_equal_hook)(long long, const logos_shape *, long long, const logos_shape *);\n\nlong long logos_deep_copy(long long v, const logos_shape *s) {\n    if (s->form == 22) return logos_tower_copy_hook(v);\n    if (s->form == 0 || (s->form >= 7 && s->form <= 9) || s->form >= 16 || !v) return v;\n    switch (s->form) {\n        case 1:\n        case 11:\n        case 12:\n        case 10: {\n            const logos_seq *a = (const logos_seq *)v;\n            logos_seq *c = logos_seq_new();\n            for (long long i = 0; i < a->len; i++) {\n                const logos_shape *cell = (const logos_shape *)s->parts[s->n == 1 ? 0 : i];\n                logos_seq_push_inplace(c, logos_deep_copy(a->data[i], cell));\n            }\n            return (long long)c;\n        }\n        case 2: {\n            const logos_map *a = (const logos_map *)v;\n            logos_map *c = logos_map_dup(a);\n            for (long long i = 0; i < a->len; i++) {\n                c->keys[i] = logos_deep_copy(a->keys[i], (const logos_shape *)s->parts[0]);\n                c->vals[i] = logos_deep_copy(a->vals[i], (const logos_shape *)s->parts[1]);\n            }\n            return (long long)c;\n        }\n        case 3:\n        case 13:\n        case 14: {\n            const logos_seq *a = (const logos_seq *)v;\n            const logos_variant *ctor = 0;\n            for (long long i = 0; i < s->n; i++) {\n                const logos_variant *r = (const logos_variant *)s->parts[i];\n                if (r->tag == a->data[0]) ctor = r;\n            }\n            logos_seq *c = logos_seq_new();\n            for (long long i = 0; i < a->len; i++) {\n                long long cell = a->data[i];\n                if (i > 0 && ctor && i - 1 < ctor->n) cell = logos_deep_copy(cell, ctor->parts[i - 1]);\n                logos_seq_push_inplace(c, cell);\n            }\n            return (long long)c;\n        }\n        default: return (long long)logos_crdt_clone((const logos_crdt *)v);\n    }\n}\n\n/* Whether `a` and `b`, two values of shape `s`, are equal by structure. */\nint logos_deep_eq(long long a, long long b, const logos_shape *s) {\n    switch (s->form) {\n        case 0: case 16: case 17: case 18: case 19: case 20: case 23: case 24: return a == b;\n        case 22: return logos_tower_equal_hook(a, s, b, s);\n        case 7: case 21: return strcmp((const char *)a, (const char *)b) == 0;\n        case 8: { double x, y; memcpy(&x, &a, 8); memcpy(&y, &b, 8); return x == y; }\n        case 9: return logos_ldec_cmp(a, 1, b, 1) == 0;\n    }\n    /* Only the VM\'s identity-bearing collections short-circuit on identity. A record, tuple or\n       enum still compares its fields, so an aliased NaN payload is unequal to itself. */\n    if (a == b && (s->form == 1 || s->form == 2 || s->form == 10)) return 1;\n    if (!a || !b) return 0;\n    switch (s->form) {\n        case 1:\n        case 11:\n        case 12: {\n            const logos_seq *x = (const logos_seq *)a, *y = (const logos_seq *)b;\n            if (x->len != y->len) return 0;\n            for (long long i = 0; i < x->len; i++) {\n                if (!logos_deep_eq(x->data[i], y->data[i], (const logos_shape *)s->parts[s->n == 1 ? 0 : i])) return 0;\n            }\n            return 1;\n        }\n        case 10: {\n            const logos_seq *x = (const logos_seq *)a, *y = (const logos_seq *)b;\n            if (x->len != y->len) return 0;\n            for (long long i = 0; i < x->len; i++) {\n                long long j = 0;\n                while (j < y->len && !logos_deep_eq(x->data[i], y->data[j], (const logos_shape *)s->parts[0])) j++;\n                if (j == y->len) return 0;\n            }\n            return 1;\n        }\n        case 2: {\n            const logos_map *x = (const logos_map *)a, *y = (const logos_map *)b;\n            if (x->len != y->len) return 0;\n            for (long long i = 0; i < x->len; i++) {\n                long long j = 0;\n                while (j < y->len && !logos_deep_eq(x->keys[i], y->keys[j], (const logos_shape *)s->parts[0])) j++;\n                if (j == y->len || !logos_deep_eq(x->vals[i], y->vals[j], (const logos_shape *)s->parts[1])) return 0;\n            }\n            return 1;\n        }\n        case 3:\n        case 13:\n        case 14: {\n            const logos_seq *x = (const logos_seq *)a, *y = (const logos_seq *)b;\n            if (x->data[0] != y->data[0] || x->len != y->len) return 0;\n            const logos_variant *ctor = 0;\n            for (long long i = 0; i < s->n; i++) {\n                const logos_variant *r = (const logos_variant *)s->parts[i];\n                if (r->tag == x->data[0]) ctor = r;\n            }\n            for (long long i = 1; i < x->len; i++) {\n                if (ctor && i - 1 < ctor->n ? !logos_deep_eq(x->data[i], y->data[i], ctor->parts[i - 1]) : x->data[i] != y->data[i]) return 0;\n            }\n            return 1;\n        }\n        default: return logos_crdt_sum((const logos_crdt *)a) == logos_crdt_sum((const logos_crdt *)b);\n    }\n}\n\n/* Cross-kind structural equality retains both layouts. Int and Float cells use exact numeric\n   comparison, never an interpretation of one kind\'s bits as another kind\'s value. */\nint logos_deep_eq_pair(long long a, long long b, const logos_shape *s, const logos_shape *t) {\n    if (s == t) return logos_deep_eq(a, b, s);\n    if (s->form == 22 || t->form == 22) return logos_tower_equal_hook(a, s, b, t);\n    if (s->form == 6) return logos_deep_eq_pair(logos_crdt_sum((const logos_crdt *)a), b, &(logos_shape){0, 0, 0}, t);\n    if (t->form == 6) return logos_deep_eq_pair(a, logos_crdt_sum((const logos_crdt *)b), s, &(logos_shape){0, 0, 0});\n    if (s->form == 0 && t->form == 0) return a == b;\n    if ((s->form == 0 && t->form == 8) || (s->form == 8 && t->form == 0)) {\n        long long bits = s->form == 8 ? a : b;\n        double f; memcpy(&f, &bits, 8);\n        return logos_cmp_i64_f64_rel(s->form == 0 ? a : b, f, 0, 4);\n    }\n    if ((s->form == 9 && t->form == 0) || (s->form == 0 && t->form == 9)) {\n        return logos_ldec_cmp(a, s->form == 9, b, t->form == 9) == 0;\n    }\n    if ((s->form == 9 && t->form == 8) || (s->form == 8 && t->form == 9)) {\n        long long bits = s->form == 8 ? a : b;\n        double f; memcpy(&f, &bits, 8);\n        return logos_ldec_cmp_f64(s->form == 9 ? a : b, f) == 0;\n    }\n    if (s->form != t->form || !a || !b) return 0;\n    switch (s->form) {\n        case 1:\n        case 11: {\n            const logos_seq *x = (const logos_seq *)a, *y = (const logos_seq *)b;\n            if (x->len != y->len) return 0;\n            for (long long i = 0; i < x->len; i++) {\n                const logos_shape *u = (const logos_shape *)s->parts[s->n == 1 ? 0 : i];\n                const logos_shape *v = (const logos_shape *)t->parts[t->n == 1 ? 0 : i];\n                if (!logos_deep_eq_pair(x->data[i], y->data[i], u, v)) return 0;\n            }\n            return 1;\n        }\n        case 2: {\n            const logos_map *x = (const logos_map *)a, *y = (const logos_map *)b;\n            if (x->len != y->len) return 0;\n            for (long long i = 0; i < x->len; i++) {\n                long long j = 0;\n                while (j < y->len && !logos_deep_eq_pair(x->keys[i], y->keys[j],\n                    (const logos_shape *)s->parts[0], (const logos_shape *)t->parts[0])) j++;\n                if (j == y->len || !logos_deep_eq_pair(x->vals[i], y->vals[j],\n                    (const logos_shape *)s->parts[1], (const logos_shape *)t->parts[1])) return 0;\n            }\n            return 1;\n        }\n        case 13:\n        case 14: {\n            const logos_seq *x = (const logos_seq *)a, *y = (const logos_seq *)b;\n            if (x->len != y->len || x->data[0] != y->data[0]) return 0;\n            const logos_variant *u = 0, *v = 0;\n            for (long long i = 0; i < s->n; i++) {\n                const logos_variant *r = (const logos_variant *)s->parts[i];\n                if (r->tag == x->data[0]) u = r;\n            }\n            for (long long i = 0; i < t->n; i++) {\n                const logos_variant *r = (const logos_variant *)t->parts[i];\n                if (r->tag == y->data[0]) v = r;\n            }\n            if (!u || !v || u->n != v->n || x->len != u->n + 1) return 0;\n            for (long long i = 0; i < u->n; i++) {\n                if (!logos_deep_eq_pair(x->data[i+1], y->data[i+1], u->parts[i], v->parts[i])) return 0;\n            }\n            return 1;\n        }\n        /* Different nominal records/enums or different scalar kinds cannot compare equal. */\n        default: return 0;\n    }\n}\n\n/* How a value of shape `s` displays, the VM\'s `to_display_string`: a scalar as `Show` prints it, a sequence as\n   `[a, b]`, a set as `{a, b}`, a tuple as `(a, b)` and a map as `{k: v}`, each part by its own shape. */\ntypedef struct { char *text; size_t len, cap; } logos_text_buf;\n\nstatic void logos_buf_put(logos_text_buf *b, const char *s) {\n    size_t n = strlen(s);\n    if (b->len + n + 1 > b->cap) {\n        size_t cap = b->cap * 2 > b->len + n + 1 ? b->cap * 2 : b->len + n + 1;\n        b->text = (char *)lc_gc_realloc_atomic(b->text, cap);\n        b->cap = cap;\n    }\n    memcpy(b->text + b->len, s, n + 1);\n    b->len += n;\n}\n\nstatic void logos_shaped_into(logos_text_buf *b, long long v, const logos_shape *s);\n\nstatic void logos_parts_into(logos_text_buf *b, const logos_seq *a, const logos_shape *s, const char *open, const char *close) {\n    logos_buf_put(b, open);\n    for (long long i = 0; i < a->len; i++) {\n        if (i) logos_buf_put(b, \", \");\n        logos_shaped_into(b, a->data[i], (const logos_shape *)s->parts[s->n == 1 ? 0 : i]);\n    }\n    logos_buf_put(b, close);\n}\n\nstatic void logos_shaped_into(logos_text_buf *b, long long v, const logos_shape *s) {\n    char *made = 0;\n    switch (s->form) {\n        case 0: case 19: made = logos_val_to_str(v, 0); break;\n        case 16: made = logos_val_to_str(v, 2); break;\n        case 7: logos_buf_put(b, (const char *)v); return;\n        case 8: made = logos_val_to_str(v, 1); break;\n        case 9: made = logos_val_to_str(v, 4); break;\n        case 17: made = logos_val_to_str(v, 5); break;\n        case 18: made = logos_val_to_str(v, 6); break;\n        case 21: made = logos_val_to_str(v, 8); break;\n        case 6: made = logos_val_to_str(logos_crdt_sum((const logos_crdt *)v), 0); break;\n        case 22: made = logos_tower_text_hook(v); break;\n        case 23: logos_buf_put(b, \"nothing\"); return;\n        case 1: logos_parts_into(b, (const logos_seq *)v, s, \"[\", \"]\"); return;\n        case 10: logos_parts_into(b, (const logos_seq *)v, s, \"{\", \"}\"); return;\n        case 11: logos_parts_into(b, (const logos_seq *)v, s, \"(\", \")\"); return;\n        case 2: {\n            const logos_map *m = (const logos_map *)v;\n            logos_buf_put(b, \"{\");\n            for (long long i = 0; i < m->len; i++) {\n                if (i) logos_buf_put(b, \", \");\n                logos_shaped_into(b, m->keys[i], (const logos_shape *)s->parts[0]);\n                logos_buf_put(b, \": \");\n                logos_shaped_into(b, m->vals[i], (const logos_shape *)s->parts[1]);\n            }\n            logos_buf_put(b, \"}\");\n            return;\n        }\n        default: logos_fatalf(\"the RISC-V runtime has no display for a value of shape form %lld\", s->form);\n    }\n    logos_buf_put(b, made);\n    lc_gc_free(made);\n}\n\nchar *logos_shaped_str(long long v, const logos_shape *s) {\n    logos_text_buf b = {0, 0, 0};\n    logos_buf_put(&b, \"\");\n    logos_shaped_into(&b, v, s);\n    return b.text;\n}\n\nvoid logos_show_shaped(long long v, const logos_shape *s) {\n    char *text = logos_shaped_str(v, s);\n    printf(\"%s\\n\", text);\n    lc_gc_free(text);\n}\n\n/* Snapshot iterator stack (for `Repeat for x in xs`). A snapshot is just the handle: the iterated\n * register\'s handle escapes into the iterator, which clears the register\'s owned flag, so a mutation of it\n * inside the loop copies first and the iterated list never changes under the iterator. Each task iterates\n * on a stack of its own, so a task that yields inside a loop resumes it where it left off (`logos_iters`). */\ntypedef struct { logos_seq *seq[256]; long long idx[256]; int top; } logos_iter_stack;\nstatic logos_iter_stack *logos_iters(void);\nvoid logos_iter_begin(logos_seq *s) {\n    logos_iter_stack *it = logos_iters();\n    it->seq[it->top] = s;\n    it->idx[it->top] = 0;\n    it->top++;\n}\nint logos_iter_has(void) {\n    logos_iter_stack *it = logos_iters();\n    int t = it->top - 1;\n    return it->idx[t] < it->seq[t]->len;\n}\nlong long logos_iter_take(void) {\n    logos_iter_stack *it = logos_iters();\n    int t = it->top - 1;\n    return it->seq[t]->data[it->idx[t]++];\n}\nvoid logos_iter_end(void) { logos_iters()->top--; }\n\n/* ---- Deterministic cooperative concurrency: the C family\'s scheduler core under `ucontext` ---- */\n#define LOGOS_FN static __attribute__((unused))\n#define LOGOS_VAR static\n#define LOGOS_API\n#define logos_alloc(n) lc_gc_calloc(1, (n))\n#define logos_release(p) lc_gc_free(p)\n#define LOGOS_STACK_ENTER(lo, hi) lc_gc_stack_enter((lo), (hi))\n#define LOGOS_STACK_LEAVE() lc_gc_stack_leave()\n#define LOGOS_TASK_TIER ucontext_t ctx; void *stack; void *fn; long long nargs; long long *args; logos_iter_stack *iters;\nstatic long long logos_riscv_call(void *fn, long long n, const long long *a);\n#define LOGOS_TASK_CALL(t) logos_riscv_call((t)->fn, (t)->nargs, (t)->args)\n/* The LOGOS scheduler \u{2014} `logicaffeine_runtime::Scheduler::process_step`, ported step for step.\n *\n * ONE policy core for every C-family tier: the coroutine runtimes (host C, RISC-V) and the stackless\n * frames (CUDA, the host bytecode walker). An operation is a state transition over the task table: it\n * mutates the queues and leaves the task it was handed either READY at the back of the ready queue,\n * holding the value it resumes with, or blocked off the queue. A tier supplies only the yield \u{2014} switching\n * back to its scheduler loop\'s context, or saving a frame\'s pc and returning \u{2014} and reads `resume`\n * when the task runs again. Every concurrency operation is a scheduling point, as it is in the runtime.\n *\n * Before this text a tier defines:\n *   LOGOS_FN         the qualifier of a core function (`static`, or `__device__ static`)\n *   LOGOS_VAR        the qualifier of a core variable\n *   logos_alloc(n)   / logos_release(p)\n *   LOGOS_TASK_TIER  the tier\'s own fields of a task: its context, or its frame\n * and may define LOGOS_SCHED_POLICY and LOGOS_CHAN_DEFAULT_CAP (defaults below: the runtime\'s own).\n */\n\n#ifndef LOGOS_SCHED_POLICY\n#define LOGOS_SCHED_FIFO 0\n#define LOGOS_SCHED_LIFO 1\n#define LOGOS_SCHED_ROUNDROBIN 2\n#define LOGOS_SCHED_RANDOM 3\n#define LOGOS_SCHED_PRIORITY 4\n#define LOGOS_SCHED_POLICY LOGOS_SCHED_FIFO\n#endif\n/* A pipe with no written capacity holds `SchedulerConfig::default_channel_capacity` values. */\n#ifndef LOGOS_CHAN_DEFAULT_CAP\n#define LOGOS_CHAN_DEFAULT_CAP 32LL\n#endif\n#ifndef LOGOS_SEL_MAX\n#define LOGOS_SEL_MAX 16\n#endif\n\n#define LOGOS_READY 0\n#define LOGOS_BLOCKED_RECV 1\n#define LOGOS_BLOCKED_SEND 2\n#define LOGOS_BLOCKED_TIMER 3\n#define LOGOS_BLOCKED_SELECT 4\n#define LOGOS_BLOCKED_AWAIT 5\n#define LOGOS_DONE 6\n\n#define LOGOS_ARM_RECV 0\n#define LOGOS_ARM_AFTER 1\n\ntypedef struct logos_task logos_task;\ntypedef struct logos_chan logos_chan;\n\n/* Tasks in arrival order, oldest first. */\ntypedef struct {\n    logos_task **at;\n    int head, len, cap;\n} logos_queue;\n\nstruct logos_task {\n    int state;\n    long long resume;         /* the value the operation that woke it delivers */\n    int resume_nothing;       /* it delivered `nothing`: a closed pipe, an empty try, an awaited task */\n    int selected_arm;         /* the arm a select resolved to */\n    long long send_value;     /* the value a blocked send holds */\n    logos_chan *waits_on;     /* the pipe a blocked receive or send waits on */\n    logos_task *awaits;       /* the task a blocked await waits for */\n    int sel_n;                /* a waiting select\'s arms, in declaration order */\n    int sel_kind[LOGOS_SEL_MAX];\n    logos_chan *sel_chan[LOGOS_SEL_MAX];\n    logos_queue awaiters;     /* the tasks awaiting this one, in the order they began to */\n    long long priority;\n    LOGOS_TASK_TIER\n};\n\nstruct logos_chan {\n    long long *buf;\n    int head, len, cap_alloc;\n    long long capacity;\n    int closed;\n    logos_queue receivers;    /* blocked receives; a waiting select once per arm naming this pipe */\n    logos_queue senders;      /* blocked sends, each holding its value in `send_value` */\n};\n\ntypedef struct {\n    long long fire_at;\n    logos_task *task;\n    int arm;                  /* the select arm it resolves, or -1 for a `Sleep` */\n} logos_timer;\n\nLOGOS_VAR logos_queue logos_ready_q;\n/* Finished tasks retain their storage until the scheduler has left their execution context. */\nLOGOS_VAR logos_queue logos_retired_q;\nLOGOS_VAR long long logos_clock = 0;\nLOGOS_VAR unsigned long long logos_rng = 0;\nLOGOS_VAR logos_timer *logos_timers = 0;\nLOGOS_VAR int logos_timer_n = 0, logos_timer_cap = 0;\nLOGOS_VAR logos_task **logos_all = 0;\nLOGOS_VAR int logos_all_n = 0, logos_all_cap = 0;\n/* The first failure of any task; the run fails with it once every other task is quiescent. */\nLOGOS_VAR const char *logos_failure = 0;\n\n/* ---- the chooser: `SeededRng`, the runtime\'s one source of scheduling choice ---- */\n\nLOGOS_FN void logos_seed(unsigned long long seed) { logos_rng = seed; }\n\nLOGOS_FN unsigned long long logos_rng_next(void) {\n    logos_rng += 0x9E3779B97F4A7C15ULL;\n    unsigned long long z = logos_rng;\n    z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;\n    z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;\n    return z ^ (z >> 31);\n}\n\n/* An index in [0, n); one option draws nothing, as `SeededRng::below` does. */\nLOGOS_FN int logos_choose(int n) {\n    if (n <= 1) return 0;\n    return (int)(logos_rng_next() % (unsigned long long)n);\n}\n\n/* ---- queues ---- */\n\nLOGOS_FN logos_task *logos_queue_at(logos_queue *q, int k) { return q->at[(q->head + k) % q->cap]; }\n\nLOGOS_FN void logos_queue_push(logos_queue *q, logos_task *t) {\n    if (q->len == q->cap) {\n        int cap = q->cap ? q->cap * 2 : 8;\n        logos_task **at = (logos_task **)logos_alloc((unsigned long)cap * sizeof(logos_task *));\n        for (int i = 0; i < q->len; i++) at[i] = logos_queue_at(q, i);\n        if (q->at) logos_release(q->at);\n        q->at = at;\n        q->head = 0;\n        q->cap = cap;\n    }\n    q->at[(q->head + q->len) % q->cap] = t;\n    q->len++;\n}\n\n/* Remove and return the k-th oldest. */\nLOGOS_FN logos_task *logos_queue_take(logos_queue *q, int k) {\n    logos_task *t = logos_queue_at(q, k);\n    if (k == 0) {\n        q->at[q->head] = 0;\n        q->head = (q->head + 1) % q->cap;\n    } else {\n        for (int i = k; i + 1 < q->len; i++) q->at[(q->head + i) % q->cap] = logos_queue_at(q, i + 1);\n        q->at[(q->head + q->len - 1) % q->cap] = 0;\n    }\n    q->len--;\n    return t;\n}\n\nLOGOS_FN logos_task *logos_queue_pop(logos_queue *q) { return q->len ? logos_queue_take(q, 0) : 0; }\n\n/* Drop every entry that is `t`, keeping the others in order. */\nLOGOS_FN void logos_queue_remove(logos_queue *q, logos_task *t) {\n    int kept = 0;\n    for (int i = 0; i < q->len; i++) {\n        logos_task *x = logos_queue_at(q, i);\n        if (x != t) q->at[(q->head + kept++) % q->cap] = x;\n    }\n    for (int i = kept; i < q->len; i++) q->at[(q->head + i) % q->cap] = 0;\n    q->len = kept;\n}\n\n/* ---- timers ---- */\n\nLOGOS_FN void logos_timer_add(long long fire_at, logos_task *t, int arm) {\n    if (logos_timer_n == logos_timer_cap) {\n        int cap = logos_timer_cap ? logos_timer_cap * 2 : 16;\n        logos_timer *at = (logos_timer *)logos_alloc((unsigned long)cap * sizeof(logos_timer));\n        for (int i = 0; i < logos_timer_n; i++) at[i] = logos_timers[i];\n        if (logos_timers) logos_release(logos_timers);\n        logos_timers = at;\n        logos_timer_cap = cap;\n    }\n    logos_timers[logos_timer_n].fire_at = fire_at;\n    logos_timers[logos_timer_n].task = t;\n    logos_timers[logos_timer_n].arm = arm;\n    logos_timer_n++;\n}\n\n/* Drop every timer of `t`, keeping the others in order. */\nLOGOS_FN void logos_timer_remove(logos_task *t) {\n    int kept = 0;\n    for (int i = 0; i < logos_timer_n; i++) {\n        if (logos_timers[i].task != t) logos_timers[kept++] = logos_timers[i];\n    }\n    for (int i = kept; i < logos_timer_n; i++) logos_timers[i].task = 0;\n    logos_timer_n = kept;\n}\n\n/* ---- tasks ---- */\n\nLOGOS_FN void logos_mark_ready(logos_task *t, long long value, int nothing) {\n    t->waits_on = 0;\n    t->awaits = 0;\n    t->send_value = 0;\n    t->resume = value;\n    t->resume_nothing = nothing;\n    t->state = LOGOS_READY;\n    logos_queue_push(&logos_ready_q, t);\n}\n\n/* A new task joins the table ready \u{2014} the runtime\'s `spawn_inner`. */\nLOGOS_FN void logos_task_begin(logos_task *t) {\n    t->resume = 0;\n    t->resume_nothing = 1;\n    t->selected_arm = -1;\n    t->send_value = 0;\n    t->waits_on = 0;\n    t->awaits = 0;\n    t->sel_n = 0;\n    t->awaiters.at = 0;\n    t->awaiters.head = t->awaiters.len = t->awaiters.cap = 0;\n    if (logos_all_n == logos_all_cap) {\n        int cap = logos_all_cap ? logos_all_cap * 2 : 16;\n        logos_task **at = (logos_task **)logos_alloc((unsigned long)cap * sizeof(logos_task *));\n        for (int i = 0; i < logos_all_n; i++) at[i] = logos_all[i];\n        if (logos_all) logos_release(logos_all);\n        logos_all = at;\n        logos_all_cap = cap;\n    }\n    logos_all[logos_all_n++] = t;\n    t->state = LOGOS_READY;\n    logos_queue_push(&logos_ready_q, t);\n}\n\n/* Wake everything awaiting `t`, which has finished: each resumes with `nothing`, the result every\n   C-family task carries (a task exits `Nothing` on the tree-walker). */\nLOGOS_FN void logos_complete(logos_task *t) {\n    t->resume = 0;\n    t->resume_nothing = 1;\n    t->waits_on = 0;\n    t->awaits = 0;\n    t->send_value = 0;\n    for (int i = 0; i < LOGOS_SEL_MAX; i++) t->sel_chan[i] = 0;\n    t->sel_n = 0;\n    logos_task *w;\n    while ((w = logos_queue_pop(&t->awaiters))) logos_mark_ready(w, 0, 1);\n    logos_release(t->awaiters.at);\n    t->awaiters.at = 0;\n    t->awaiters.cap = t->awaiters.head = t->awaiters.len = 0;\n    int kept = 0;\n    for (int i = 0; i < logos_all_n; i++) {\n        if (logos_all[i] != t) logos_all[kept++] = logos_all[i];\n    }\n    for (int i = kept; i < logos_all_n; i++) logos_all[i] = 0;\n    logos_all_n = kept;\n    logos_queue_push(&logos_retired_q, t);\n}\n\n/* ---- pipes ---- */\n\nLOGOS_FN int logos_chan_has_room(logos_chan *c) { return c->len < c->capacity; }\n\nLOGOS_FN int logos_chan_can_recv(logos_chan *c) { return c->len > 0 || c->senders.len > 0 || c->closed; }\n\nLOGOS_FN void logos_chan_buffer(logos_chan *c, long long v) {\n    if (c->len == c->cap_alloc) {\n        int cap = c->cap_alloc * 2;\n        long long *buf = (long long *)logos_alloc((unsigned long)cap * sizeof(long long));\n        for (int i = 0; i < c->len; i++) buf[i] = c->buf[(c->head + i) % c->cap_alloc];\n        logos_release(c->buf);\n        c->buf = buf;\n        c->head = 0;\n        c->cap_alloc = cap;\n    }\n    c->buf[(c->head + c->len) % c->cap_alloc] = v;\n    c->len++;\n}\n\nLOGOS_FN int logos_chan_unbuffer(logos_chan *c, long long *v) {\n    if (c->len == 0) return 0;\n    *v = c->buf[c->head];\n    c->buf[c->head] = 0;\n    c->head = (c->head + 1) % c->cap_alloc;\n    c->len--;\n    return 1;\n}\n\nLOGOS_FN void logos_refill_from_blocked_sender(logos_chan *c) {\n    if (!logos_chan_has_room(c)) return;\n    logos_task *s = logos_queue_pop(&c->senders);\n    if (s) {\n        logos_chan_buffer(c, s->send_value);\n        logos_mark_ready(s, 0, 1);\n    }\n}\n\n/* Withdraw every registration a woken select made \u{2014} on each pipe it names, the one that woke it too,\n   since a select naming one pipe in two arms waits on it twice \u{2014} and its timeouts. */\nLOGOS_FN void logos_cancel_select(logos_task *t) {\n    for (int i = 0; i < t->sel_n; i++) {\n        if (t->sel_kind[i] == LOGOS_ARM_RECV) logos_queue_remove(&t->sel_chan[i]->receivers, t);\n        t->sel_chan[i] = 0;\n    }\n    t->sel_n = 0;\n    logos_timer_remove(t);\n}\n\n/* The first arm of `t`\'s waiting select that receives from `c`. */\nLOGOS_FN int logos_arm_on(logos_task *t, logos_chan *c) {\n    for (int i = 0; i < t->sel_n; i++) {\n        if (t->sel_kind[i] == LOGOS_ARM_RECV && t->sel_chan[i] == c) return i;\n    }\n    return 0;\n}\n\nLOGOS_FN void logos_resolve_select(logos_task *t, int arm, long long value, int nothing) {\n    t->resume = value;\n    t->resume_nothing = nothing;\n    t->selected_arm = arm;\n    t->state = LOGOS_READY;\n    logos_queue_push(&logos_ready_q, t);\n    logos_cancel_select(t);\n}\n\nLOGOS_FN void logos_deliver(logos_task *r, logos_chan *c, long long v) {\n    if (r->state == LOGOS_BLOCKED_SELECT) {\n        logos_resolve_select(r, logos_arm_on(r, c), v, 0);\n    } else {\n        logos_mark_ready(r, v, 0);\n    }\n}\n\n/* One value from a pipe `logos_chan_can_recv` said is ready: buffered, from a blocked sender, or\n   `nothing` from a closed pipe. */\nLOGOS_FN void logos_take_one(logos_chan *c, long long *v, int *nothing) {\n    if (logos_chan_unbuffer(c, v)) {\n        *nothing = 0;\n        logos_refill_from_blocked_sender(c);\n        return;\n    }\n    logos_task *s = logos_queue_pop(&c->senders);\n    if (s) {\n        *v = s->send_value;\n        logos_mark_ready(s, 0, 1);\n        *nothing = 0;\n        return;\n    }\n    *v = 0;\n    *nothing = 1;\n}\n\n/* ---- the operations: one `process_step` arm each ---- */\n\nLOGOS_FN void logos_op_yield(logos_task *t) { logos_mark_ready(t, 0, 1); }\n\nLOGOS_FN logos_chan *logos_op_new_chan(logos_task *t, long long capacity) {\n    logos_chan *c = (logos_chan *)logos_alloc(sizeof(logos_chan));\n    c->cap_alloc = 8;\n    c->buf = (long long *)logos_alloc((unsigned long)c->cap_alloc * sizeof(long long));\n    c->head = 0;\n    c->len = 0;\n    c->capacity = capacity < 0 ? LOGOS_CHAN_DEFAULT_CAP : capacity;\n    c->closed = 0;\n    c->receivers.at = 0;\n    c->receivers.head = c->receivers.len = c->receivers.cap = 0;\n    c->senders.at = 0;\n    c->senders.head = c->senders.len = c->senders.cap = 0;\n    logos_mark_ready(t, 0, 1);\n    return c;\n}\n\n/* The child joins the ready queue, then the parent behind it: the child runs before its parent resumes. */\nLOGOS_FN void logos_op_spawn(logos_task *t, logos_task *child) {\n    logos_task_begin(child);\n    logos_mark_ready(t, 0, 1);\n}\n\nLOGOS_FN void logos_op_send(logos_task *t, logos_chan *c, long long v) {\n    logos_task *r = logos_queue_pop(&c->receivers);\n    if (r) {\n        logos_deliver(r, c, v);\n        logos_mark_ready(t, 0, 1);\n        return;\n    }\n    if (logos_chan_has_room(c)) {\n        logos_chan_buffer(c, v);\n        logos_mark_ready(t, 0, 1);\n        return;\n    }\n    t->send_value = v;\n    t->waits_on = c;\n    logos_queue_push(&c->senders, t);\n    t->state = LOGOS_BLOCKED_SEND;\n}\n\nLOGOS_FN void logos_op_recv(logos_task *t, logos_chan *c) {\n    long long v;\n    if (logos_chan_unbuffer(c, &v)) {\n        logos_mark_ready(t, v, 0);\n        logos_refill_from_blocked_sender(c);\n        return;\n    }\n    logos_task *s = logos_queue_pop(&c->senders);\n    if (s) {\n        logos_mark_ready(t, s->send_value, 0);\n        logos_mark_ready(s, 0, 1);\n        return;\n    }\n    if (c->closed) {\n        logos_mark_ready(t, 0, 1);\n        return;\n    }\n    t->waits_on = c;\n    logos_queue_push(&c->receivers, t);\n    t->state = LOGOS_BLOCKED_RECV;\n}\n\n/* Never blocks: resumes with 1 when the value was taken, else 0 (the value is dropped). */\nLOGOS_FN void logos_op_try_send(logos_task *t, logos_chan *c, long long v) {\n    logos_task *r = logos_queue_pop(&c->receivers);\n    if (r) {\n        logos_deliver(r, c, v);\n        logos_mark_ready(t, 1, 0);\n        return;\n    }\n    if (logos_chan_has_room(c)) {\n        logos_chan_buffer(c, v);\n        logos_mark_ready(t, 1, 0);\n        return;\n    }\n    logos_mark_ready(t, 0, 0);\n}\n\n/* Never blocks: resumes with a value, or with `nothing` when there is none. */\nLOGOS_FN void logos_op_try_recv(logos_task *t, logos_chan *c) {\n    long long v;\n    if (logos_chan_unbuffer(c, &v)) {\n        logos_mark_ready(t, v, 0);\n        logos_refill_from_blocked_sender(c);\n        return;\n    }\n    logos_task *s = logos_queue_pop(&c->senders);\n    if (s) {\n        logos_mark_ready(t, s->send_value, 0);\n        logos_mark_ready(s, 0, 1);\n        return;\n    }\n    logos_mark_ready(t, 0, 1);\n}\n\n/* A select: among its receive arms ready now, one wins \u{2014} the seeded chooser picks when several are \u{2014}\n   else it waits on every receive arm and every timeout at once. */\nLOGOS_FN void logos_op_select(logos_task *t, int n, const int *kind, logos_chan *const *chan, const long long *ticks) {\n    int ready[LOGOS_SEL_MAX];\n    int k = 0;\n    for (int i = 0; i < n; i++) {\n        if (kind[i] == LOGOS_ARM_RECV && logos_chan_can_recv(chan[i])) ready[k++] = i;\n    }\n    if (k > 0) {\n        int arm = ready[logos_choose(k)];\n        long long v;\n        int nothing;\n        logos_take_one(chan[arm], &v, &nothing);\n        t->resume = v;\n        t->resume_nothing = nothing;\n        t->selected_arm = arm;\n        t->state = LOGOS_READY;\n        logos_queue_push(&logos_ready_q, t);\n        return;\n    }\n    t->sel_n = n;\n    for (int i = 0; i < n; i++) {\n        t->sel_kind[i] = kind[i];\n        t->sel_chan[i] = kind[i] == LOGOS_ARM_RECV ? chan[i] : 0;\n        if (kind[i] == LOGOS_ARM_RECV) {\n            logos_queue_push(&chan[i]->receivers, t);\n        } else {\n            logos_timer_add(logos_clock + (ticks[i] < 0 ? 0 : ticks[i]), t, i);\n        }\n    }\n    t->state = LOGOS_BLOCKED_SELECT;\n}\n\nLOGOS_FN void logos_op_sleep(logos_task *t, long long ticks) {\n    logos_timer_add(logos_clock + (ticks < 0 ? 0 : ticks), t, -1);\n    t->state = LOGOS_BLOCKED_TIMER;\n}\n\nLOGOS_FN void logos_op_await(logos_task *t, logos_task *target) {\n    if (!target || target->state == LOGOS_DONE) {\n        logos_mark_ready(t, 0, 1);\n        return;\n    }\n    t->awaits = target;\n    logos_queue_push(&target->awaiters, t);\n    t->state = LOGOS_BLOCKED_AWAIT;\n}\n\n/* `Stop h`: the target leaves every queue it waits in and finishes, waking its awaiters with\n   `nothing`; the stopping task goes on. A finished target is untouched. */\nLOGOS_FN void logos_op_abort(logos_task *t, logos_task *target) {\n    if (target && target->state != LOGOS_DONE) {\n        logos_queue_remove(&logos_ready_q, target);\n        switch (target->state) {\n            case LOGOS_BLOCKED_RECV: logos_queue_remove(&target->waits_on->receivers, target); break;\n            case LOGOS_BLOCKED_SEND: logos_queue_remove(&target->waits_on->senders, target); break;\n            case LOGOS_BLOCKED_SELECT:\n                for (int i = 0; i < target->sel_n; i++) {\n                    if (target->sel_kind[i] == LOGOS_ARM_RECV) logos_queue_remove(&target->sel_chan[i]->receivers, target);\n                }\n                break;\n            case LOGOS_BLOCKED_AWAIT: logos_queue_remove(&target->awaits->awaiters, target); break;\n            default: break;\n        }\n        logos_timer_remove(target);\n        target->state = LOGOS_DONE;\n        logos_complete(target);\n    }\n    logos_mark_ready(t, 0, 1);\n}\n\n/* `Close c`: every blocked receive resumes with `nothing` \u{2014} a waiting select once, on its first arm\n   naming `c` \u{2014} and later receives of the drained pipe answer `nothing` too. */\nLOGOS_FN void logos_op_close(logos_task *t, logos_chan *c) {\n    c->closed = 1;\n    int n = c->receivers.len;\n    logos_task **waiting = n ? (logos_task **)logos_alloc((unsigned long)n * sizeof(logos_task *)) : 0;\n    for (int i = 0; i < n; i++) waiting[i] = logos_queue_at(&c->receivers, i);\n    for (int i = 0; i < c->receivers.cap; i++) c->receivers.at[i] = 0;\n    c->receivers.len = 0;\n    c->receivers.head = 0;\n    for (int i = 0; i < n; i++) {\n        logos_task *r = waiting[i];\n        if (r->state == LOGOS_BLOCKED_SELECT) {\n            logos_resolve_select(r, logos_arm_on(r, c), 0, 1);\n        } else if (r->state == LOGOS_BLOCKED_RECV) {\n            logos_mark_ready(r, 0, 1);\n        }\n    }\n    if (waiting) logos_release(waiting);\n    logos_mark_ready(t, 0, 1);\n}\n\n/* The task\'s body returned. */\nLOGOS_FN void logos_op_exit(logos_task *t) {\n    t->state = LOGOS_DONE;\n    logos_complete(t);\n}\n\n/* The task failed: the run keeps its first failure and every other task still runs to quiescence. */\nLOGOS_FN void logos_op_fail(logos_task *t, const char *message) {\n    if (!logos_failure) logos_failure = message;\n    logos_op_exit(t);\n}\n\n/* ---- the scheduler loop\'s two moves ---- */\n\n/* The next task to run, by the policy knob. */\nLOGOS_FN logos_task *logos_pick_ready(void) {\n    int n = logos_ready_q.len;\n    if (n == 0) return 0;\n    int k = 0;\n#if LOGOS_SCHED_POLICY == LOGOS_SCHED_LIFO\n    k = n - 1;\n#elif LOGOS_SCHED_POLICY == LOGOS_SCHED_RANDOM\n    k = logos_choose(n);\n#elif LOGOS_SCHED_POLICY == LOGOS_SCHED_PRIORITY\n    long long best = logos_queue_at(&logos_ready_q, 0)->priority;\n    for (int i = 1; i < n; i++) {\n        long long p = logos_queue_at(&logos_ready_q, i)->priority;\n        if (p > best) {\n            best = p;\n            k = i;\n        }\n    }\n#endif\n    return logos_queue_take(&logos_ready_q, k);\n}\n\n/* Nothing is ready: the clock jumps to the earliest timer and every timer due then fires, same-tick\n   ties in the order the seeded chooser draws. Answers 0 when no timer is pending. */\nLOGOS_FN int logos_advance_timers(void) {\n    if (logos_timer_n == 0) return 0;\n    long long earliest = logos_timers[0].fire_at;\n    for (int i = 1; i < logos_timer_n; i++) {\n        if (logos_timers[i].fire_at < earliest) earliest = logos_timers[i].fire_at;\n    }\n    logos_clock = earliest;\n    int due_n = 0;\n    for (int i = 0; i < logos_timer_n; i++) due_n += logos_timers[i].fire_at == earliest;\n    logos_timer *due = (logos_timer *)logos_alloc((unsigned long)due_n * sizeof(logos_timer));\n    int d = 0, kept = 0;\n    for (int i = 0; i < logos_timer_n; i++) {\n        if (logos_timers[i].fire_at == earliest) {\n            due[d++] = logos_timers[i];\n        } else {\n            logos_timers[kept++] = logos_timers[i];\n        }\n    }\n    for (int i = kept; i < logos_timer_n; i++) logos_timers[i].task = 0;\n    logos_timer_n = kept;\n    int *pool = (int *)logos_alloc((unsigned long)due_n * sizeof(int));\n    for (int i = 0; i < due_n; i++) pool[i] = i;\n    int left = due_n;\n    while (left > 0) {\n        int pick = logos_choose(left);\n        logos_timer fired = due[pool[pick]];\n        for (int i = pick; i + 1 < left; i++) pool[i] = pool[i + 1];\n        left--;\n        logos_task *t = fired.task;\n        if (t->state != LOGOS_BLOCKED_TIMER && t->state != LOGOS_BLOCKED_SELECT) continue;\n        if (fired.arm >= 0) {\n            int selecting = t->state == LOGOS_BLOCKED_SELECT;\n            t->selected_arm = fired.arm;\n            t->resume = 0;\n            t->resume_nothing = 1;\n            t->state = LOGOS_READY;\n            logos_queue_push(&logos_ready_q, t);\n            if (selecting) logos_cancel_select(t);\n        } else {\n            logos_mark_ready(t, 0, 1);\n        }\n    }\n    logos_release(pool);\n    logos_release(due);\n    return 1;\n}\n\n/* At quiescence: some task never finished \u{2014} the run deadlocked. */\nLOGOS_FN int logos_deadlocked(void) {\n    for (int i = 0; i < logos_all_n; i++) {\n        if (logos_all[i]->state != LOGOS_DONE) return 1;\n    }\n    return 0;\n}\n/* The seed a host C-family run schedules under: `LOGOS_SEED` read as the Rust tier reads it\n   (`logicaffeine_system::concurrency` \u{2014} trimmed, then a u64 with an optional `+`); `otherwise` when it is\n   unset or does not parse. */\nstatic int logos_seed_space(char c) { return c == \' \' || c == \'\\t\' || c == \'\\n\' || c == \'\\r\' || c == \'\\v\' || c == \'\\f\'; }\n\nstatic unsigned long long logos_env_seed(unsigned long long otherwise) {\n    const char *s = getenv(\"LOGOS_SEED\");\n    if (!s) return otherwise;\n    while (logos_seed_space(*s)) s++;\n    if (*s == \'+\') s++;\n    unsigned long long v = 0;\n    int digits = 0;\n    for (; *s >= \'0\' && *s <= \'9\'; s++, digits++) {\n        unsigned long long d = (unsigned long long)(*s - \'0\');\n        if (v > (~0ULL - d) / 10) return otherwise;\n        v = v * 10 + d;\n    }\n    while (logos_seed_space(*s)) s++;\n    return (digits && !*s) ? v : otherwise;\n}\n/* The values a scheduler operation hands a task, in the C family\'s scalar packing: a Real crosses a pipe or a\n * task boundary as its bits, a Text as its pointer, anything else as itself; and a value-or-nothing \u{2014} what a\n * receive, a select arm, `Try to receive` and `Await \u{2026} into` read \u{2014} is `logos_opt`. Shared by every tier. */\n\n/* A Real crosses into a task as its bits, so it arrives whole. */\nLOGOS_API long long logos_real_bits(double d) {\n    long long bits;\n    memcpy(&bits, &d, sizeof bits);\n    return bits;\n}\n\nLOGOS_API double logos_bits_real(long long bits) {\n    double d;\n    memcpy(&d, &bits, sizeof d);\n    return d;\n}\n\n/* A value, or `nothing`: what a receive reads. */\ntypedef struct { long long present, value; } logos_opt;\n\n/* A value-or-nothing read as an Int: the value; `nothing` fails the task. */\nLOGOS_API long long logos_opt_int(logos_opt o) {\n    if (!o.present) logos_fatal(\"expected an Int, but the value is nothing\");\n    return o.value;\n}\n\n/* `a is b` between values that may be `nothing`: both nothing, or both the same value. */\nLOGOS_API int logos_opt_eq(logos_opt a, logos_opt b) {\n    return a.present == b.present && (!a.present || a.value == b.value);\n}\n\n/* The same, for Reals carried by their bits: equal as numbers, so `0.0` is `-0.0`. */\nLOGOS_API int logos_opt_eq_real(logos_opt a, logos_opt b) {\n    return a.present == b.present && (!a.present || logos_bits_real(a.value) == logos_bits_real(b.value));\n}\n\n/* The same, for Texts carried by their pointers: equal as text. */\nLOGOS_API int logos_opt_eq_text(logos_opt a, logos_opt b) {\n    return a.present == b.present\n        && (!a.present || strcmp((const char *)(intptr_t)a.value, (const char *)(intptr_t)b.value) == 0);\n}\n\n/* The C family\'s coroutine tier: the scheduler core (`sched_core.c`) under `ucontext`. Every task runs\n * on a stack of its own; an operation performs the core\'s step for it, then swaps back to the scheduler\n * loop, which resumes the next ready task \u{2014} so every operation is a scheduling point, as it is in the\n * runtime. Shared by host C and RISC-V, which differ in `LOGOS_API` \u{2014} the linkage of the entry points the\n * emitted code calls (static for C, external for RISC-V\'s assembly) \u{2014} and in `LOGOS_TASK_CALL`, how a task\n * body is called (RISC-V\'s take their arguments in registers).\n *\n * A task body is an entry `long long entry(const long long *args)` the tier calls by address with the\n * task\'s own copy of its launch arguments, however many there are. A run ends when nothing is ready and no\n * timer is pending: it fails with the first task failure, or \u{2014} when some task never finished \u{2014} as a\n * deadlock, the interpreter\'s words for both. */\n\n#ifndef LOGOS_STACK_ENTER\n#define LOGOS_STACK_ENTER(lo, hi) ((void)0)\n#define LOGOS_STACK_LEAVE() ((void)0)\n#endif\n\n#define LOGOS_STACK 262144\n\nstatic ucontext_t logos_sched_ctx;\nstatic logos_task *logos_current = 0;\n\nstatic void logos_yield(void) { swapcontext(&logos_current->ctx, &logos_sched_ctx); }\n\n/* A failure inside a task fails the task \u{2014} the run keeps the first, and reports it once every other task\n   is quiescent \u{2014} and the task never runs again. Installed as the runtime\'s failure hook for the run. */\nstatic void logos_task_failed(const char *message) {\n    if (!logos_current) return;\n    logos_op_fail(logos_current, message);\n    logos_yield();\n}\n\n/* How the tier calls a task body: by default an entry taking the task\'s argument array. A tier whose\n   bodies take their arguments otherwise defines `LOGOS_TASK_CALL(t)` before this file. */\n#ifndef LOGOS_TASK_CALL\n#define LOGOS_TASK_CALL(t) ((long long (*)(const long long *))(t)->fn)((t)->args)\n#endif\n\nstatic void logos_task_trampoline(void) {\n    logos_task *t = logos_current;\n    LOGOS_TASK_CALL(t);\n    logos_op_exit(t);\n}\n\nstatic logos_task *logos_make_task(void *fn, long long nargs, const long long *args) {\n    logos_task *t = (logos_task *)logos_alloc(sizeof(logos_task));\n    t->stack = logos_alloc(LOGOS_STACK);\n    t->fn = fn;\n    t->nargs = nargs;\n    t->args = (long long *)logos_alloc((nargs > 0 ? (size_t)nargs : 1) * sizeof(long long));\n    for (long long i = 0; i < nargs; i++) t->args[i] = args[i];\n    getcontext(&t->ctx);\n    t->ctx.uc_stack.ss_sp = t->stack;\n    t->ctx.uc_stack.ss_size = LOGOS_STACK;\n    t->ctx.uc_link = &logos_sched_ctx;\n    makecontext(&t->ctx, logos_task_trampoline, 0);\n    return t;\n}\n\n/* `Launch a task to f [with \u{2026}]`: the child runs before its parent resumes; answers its handle, for\n   `Stop` and `Await`. */\nLOGOS_API long long logos_spawn(void *fn, long long nargs, const long long *args) {\n    logos_task *child = logos_make_task(fn, nargs, args);\n    logos_op_spawn(logos_current, child);\n    logos_yield();\n    return (long long)(intptr_t)child;\n}\n\n/* `Await h`: resumes once `h` has finished; a task\'s result is `nothing`. */\nLOGOS_API void logos_task_await(logos_task *t) {\n    logos_op_await(logos_current, t);\n    logos_yield();\n}\n\n/* `Stop h`. */\nLOGOS_API void logos_task_abort(logos_task *t) {\n    logos_op_abort(logos_current, t);\n    logos_yield();\n}\n\n/* `Let ch be a Pipe of \u{2026}` (capacity < 0: the default). */\nLOGOS_API logos_chan *logos_chan_new(long long capacity) {\n    logos_chan *c = logos_op_new_chan(logos_current, capacity);\n    logos_yield();\n    return c;\n}\n\nLOGOS_API void logos_chan_send(logos_chan *c, long long v) {\n    logos_op_send(logos_current, c, v);\n    logos_yield();\n}\n\n/* What the running task\'s last operation resumed with. */\nstatic logos_opt logos_resumed(void) {\n    logos_opt o = { !logos_current->resume_nothing, logos_current->resume_nothing ? 0 : logos_current->resume };\n    return o;\n}\n\n/* `Receive x from c`: the value, or `nothing` once the pipe is closed and drained. */\nLOGOS_API logos_opt logos_chan_recv(logos_chan *c) {\n    logos_op_recv(logos_current, c);\n    logos_yield();\n    return logos_resumed();\n}\n\nLOGOS_API void logos_chan_close(logos_chan *c) {\n    logos_op_close(logos_current, c);\n    logos_yield();\n}\n\n/* `Try to send v into c`: 1 when it was taken, else 0. */\nLOGOS_API long long logos_chan_trysend(logos_chan *c, long long v) {\n    logos_op_try_send(logos_current, c, v);\n    logos_yield();\n    return logos_current->resume;\n}\n\n/* `Try to receive x from c`: a value, or `nothing` when none is buffered. */\nLOGOS_API logos_opt logos_chan_tryrecv(logos_chan *c) {\n    logos_op_try_recv(logos_current, c);\n    logos_yield();\n    return logos_resumed();\n}\n\n/* `Sleep n`: parks on the logical clock; a sleep of no time is no scheduling point, as the interpreter\n   makes it none. */\nLOGOS_API void logos_sleep(long long ticks) {\n    if (ticks <= 0) return;\n    logos_op_sleep(logos_current, ticks);\n    logos_yield();\n}\n\n/* `Await the first of:` \u{2014} the arms are staged in declaration order (reset, then each arm), then\n   `logos_select_wait` answers the winning arm\'s index, having written what a receive arm read \u{2014} a value,\n   or `nothing` from a closed pipe \u{2014} into its slot. The staging is copied to the waiting task\'s own stack before it yields, so another task\'s select\n   can stage in between. */\nstatic int logos_sel_n = 0;\nstatic int logos_sel_kind[LOGOS_SEL_MAX];\nstatic logos_chan *logos_sel_chan[LOGOS_SEL_MAX];\nstatic long long logos_sel_ticks[LOGOS_SEL_MAX];\nstatic logos_opt *logos_sel_slot[LOGOS_SEL_MAX];\n\nLOGOS_API void logos_select_reset(void) { logos_sel_n = 0; }\n\nLOGOS_API void logos_select_arm_recv(logos_chan *c, logos_opt *slot) {\n    logos_sel_kind[logos_sel_n] = LOGOS_ARM_RECV;\n    logos_sel_chan[logos_sel_n] = c;\n    logos_sel_ticks[logos_sel_n] = 0;\n    logos_sel_slot[logos_sel_n] = slot;\n    logos_sel_n++;\n}\n\nLOGOS_API void logos_select_arm_timeout(long long ticks) {\n    logos_sel_kind[logos_sel_n] = LOGOS_ARM_AFTER;\n    logos_sel_chan[logos_sel_n] = 0;\n    logos_sel_ticks[logos_sel_n] = ticks;\n    logos_sel_slot[logos_sel_n] = 0;\n    logos_sel_n++;\n}\n\nLOGOS_API long long logos_select_wait(void) {\n    int n = logos_sel_n;\n    int kind[LOGOS_SEL_MAX];\n    logos_chan *chan[LOGOS_SEL_MAX];\n    long long ticks[LOGOS_SEL_MAX];\n    logos_opt *slot[LOGOS_SEL_MAX];\n    for (int i = 0; i < n; i++) {\n        kind[i] = logos_sel_kind[i];\n        chan[i] = logos_sel_chan[i];\n        ticks[i] = logos_sel_ticks[i];\n        slot[i] = logos_sel_slot[i];\n    }\n    logos_sel_n = 0;\n    logos_op_select(logos_current, n, kind, chan, ticks);\n    logos_yield();\n    int arm = logos_current->selected_arm;\n    if (kind[arm] == LOGOS_ARM_RECV && slot[arm]) *slot[arm] = logos_resumed();\n    return arm;\n}\n\n/* The scheduler stack is active here; a finished task\'s stack can now be released. */\nstatic void logos_retire_completed(void) {\n    logos_task *t;\n    while ((t = logos_queue_pop(&logos_retired_q))) {\n        logos_release(t->stack);\n        logos_release(t->args);\n        t->stack = 0;\n        t->args = 0;\n        t->fn = 0;\n        t->nargs = 0;\n        memset(&t->ctx, 0, sizeof(t->ctx));\n    }\n}\n\n/* Run `main_fn` as the first task and drive the scheduler to quiescence. */\nLOGOS_API void logos_sched_bootstrap(void *main_fn) {\n    logos_seed(logos_env_seed(0));\n    logos_fail_hook = logos_task_failed;\n    logos_task_begin(logos_make_task(main_fn, 0, 0));\n    for (;;) {\n        logos_task *t = logos_pick_ready();\n        if (t) {\n            logos_current = t;\n            LOGOS_STACK_ENTER(t->stack, (char *)t->stack + LOGOS_STACK);\n            swapcontext(&logos_sched_ctx, &t->ctx);\n            LOGOS_STACK_LEAVE();\n            logos_retire_completed();\n            continue;\n        }\n        if (!logos_advance_timers()) break;\n    }\n    logos_current = 0;\n    logos_fail_hook = 0;\n    fflush(stdout);\n    if (logos_failure) {\n        fprintf(stderr, \"%s\\n\", logos_failure);\n        exit(1);\n    }\n    if (logos_deadlocked()) {\n        fprintf(stderr, \"deadlock: every task is blocked waiting\\n\");\n        exit(1);\n    }\n}\n\n/* A task body is an emitted `logos_fn_N`, which takes its arguments in a0\u{2026}a7, as every call does. */\nstatic long long logos_riscv_call(void *fn, long long n, const long long *a) {\n    switch (n) {\n        case 0: return ((long long (*)(void))fn)();\n        case 1: return ((long long (*)(long long))fn)(a[0]);\n        case 2: return ((long long (*)(long long, long long))fn)(a[0], a[1]);\n        case 3: return ((long long (*)(long long, long long, long long))fn)(a[0], a[1], a[2]);\n        case 4: return ((long long (*)(long long, long long, long long, long long))fn)(a[0], a[1], a[2], a[3]);\n        case 5: return ((long long (*)(long long, long long, long long, long long, long long))fn)(a[0], a[1], a[2], a[3], a[4]);\n        case 6: return ((long long (*)(long long, long long, long long, long long, long long, long long))fn)(a[0], a[1], a[2], a[3], a[4], a[5]);\n        case 7: return ((long long (*)(long long, long long, long long, long long, long long, long long, long long))fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);\n        default: return ((long long (*)(long long, long long, long long, long long, long long, long long, long long, long long))fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);\n    }\n}\n\n/* The running task\'s iterator stack; the program\'s own when no task runs. */\nstatic logos_iter_stack logos_iters_outside;\nstatic logos_iter_stack *logos_iters(void) {\n    if (!logos_current) return &logos_iters_outside;\n    if (!logos_current->iters) logos_current->iters = (logos_iter_stack *)lc_gc_calloc(1, sizeof(logos_iter_stack));\n    return logos_current->iters;\n}\n\nextern void *logos_fn_dispatch[];\n\n/* `Launch a task to f \u{2026}` from the emitted code: the body by its index in `logos_fn_dispatch`, the\n   arguments as the launching frame\'s contiguous slots. */\nlong long logos_spawn_fn(long long func_idx, long long nargs, const long long *args) {\n    return logos_spawn(logos_fn_dispatch[func_idx], nargs, args);\n}\n\n/* The box a select\'s receive arm resolves into: the emitted code reads it back at the wait. */\nlogos_opt *logos_opt_nothing(void) { return (logos_opt *)lc_gc_calloc(1, sizeof(logos_opt)); }\n\n/* ---- Networking \u{2014} the VM\'s offline `NetInbox`: one node, no relay ----\n   `Listen` names this node\'s inbox. `Send`/`Stream` put the message, stamped with the sender\'s inbox (empty\n   before any `Listen`), on the loopback outbox under the topic it is addressed to. `Await` needs an inbox: it\n   moves each outboxed message into the received queue when it is addressed to the inbox, dropping it\n   otherwise, then takes the first received message (or batch) from the peer it names. A lone node sends\n   nothing while it waits, so when that peer\'s message is not there the program waits for ever, as the VM\'s\n   `Await` polls for ever. A topic is canonical: `logos_net_topic`, the relay\'s `canonical_topic`. */\n\n/* Whether `s` begins with `prefix`, ASCII case folded (`to_ascii_lowercase().starts_with`). */\nstatic int logos_ascii_prefix(const char *s, const char *prefix) {\n    for (; *prefix; s++, prefix++) {\n        char c = *s >= \'A\' && *s <= \'Z\' ? (char)(*s - \'A\' + \'a\') : *s;\n        if (c != *prefix) return 0;\n    }\n    return 1;\n}\n\n/* Whether the `n` bytes at `s` parse as a `u16` (`str::parse::<u16>`: an optional `+`, then digits). */\nstatic int logos_is_u16(const char *s, size_t n) {\n    if (n && s[0] == \'+\') { s++; n--; }\n    if (!n) return 0;\n    unsigned long v = 0;\n    for (size_t i = 0; i < n; i++) {\n        if (s[i] < \'0\' || s[i] > \'9\') return 0;\n        v = v * 10 + (unsigned long)(s[i] - \'0\');\n        if (v > 65535) return 0;\n    }\n    return 1;\n}\n\n/* `multiaddr_to_ws_url` \u{2014} the `ws://` URL a libp2p multiaddr (or a ws/wss URL) names, or NULL when it names\n   none. */\nstatic char *logos_multiaddr_url(const char *addr) {\n    char *t = logos_trim(addr);\n    if (!*t) return NULL;\n    if (logos_ascii_prefix(t, \"ws://\") || logos_ascii_prefix(t, \"wss://\")) return t;\n    if (t[0] != \'/\') return NULL;\n    long long ns = 1;\n    for (const char *p = t + 1; *p; p++) ns += *p == \'/\';\n    const char **seg = (const char **)lc_gc_alloc((size_t)ns * sizeof *seg);\n    size_t *len = (size_t *)lc_gc_alloc_atomic((size_t)ns * sizeof *len);\n    const char *p = t + 1;\n    for (long long k = 0; k < ns; k++) {\n        const char *q = strchr(p, \'/\');\n        seg[k] = p;\n        len[k] = q ? (size_t)(q - p) : strlen(p);\n        p = q ? q + 1 : p + len[k];\n    }\n#define LOGOS_SEG(k, name) (len[k] == strlen(name) && strncmp(seg[k], name, len[k]) == 0)\n    const char *host = NULL, *port = NULL, *scheme = \"ws\";\n    size_t host_len = 0, port_len = 0;\n    int v6 = 0;\n    long long i = 0;\n    while (i < ns) {\n        if (LOGOS_SEG(i, \"ip4\") || LOGOS_SEG(i, \"dns\") || LOGOS_SEG(i, \"dns4\") || LOGOS_SEG(i, \"dns6\")\n            || LOGOS_SEG(i, \"dnsaddr\") || LOGOS_SEG(i, \"ip6\")) {\n            if (i + 1 >= ns || len[i + 1] == 0) return NULL;\n            v6 = LOGOS_SEG(i, \"ip6\");\n            host = seg[i + 1];\n            host_len = len[i + 1];\n            i += 2;\n        } else if (LOGOS_SEG(i, \"tcp\")) {\n            if (i + 1 >= ns || len[i + 1] == 0 || !logos_is_u16(seg[i + 1], len[i + 1])) return NULL;\n            port = seg[i + 1];\n            port_len = len[i + 1];\n            i += 2;\n        } else if (LOGOS_SEG(i, \"ws\")) {\n            scheme = \"ws\";\n            i += 1;\n        } else if (LOGOS_SEG(i, \"wss\") || LOGOS_SEG(i, \"tls\")) {\n            scheme = \"wss\";\n            i += 1;\n        } else if (LOGOS_SEG(i, \"p2p\")) {\n            i += 2;\n        } else if (LOGOS_SEG(i, \"p2p-circuit\")) {\n            i += 1;\n        } else {\n            return NULL;\n        }\n    }\n#undef LOGOS_SEG\n    if (!host || !port) return NULL;\n    size_t n = strlen(scheme) + host_len + port_len + 8;\n    char *url = (char *)lc_gc_alloc_atomic(n);\n    snprintf(url, n, v6 ? \"%s://[%.*s]:%.*s\" : \"%s://%.*s:%.*s\", scheme, (int)host_len, host, (int)port_len, port);\n    return url;\n}\n\n/* `canonical_topic` \u{2014} the relay topic an address names: its `ws://` URL, else the address trimmed. */\nchar *logos_net_topic(const char *addr) {\n    char *url = logos_multiaddr_url(addr);\n    return url ? url : logos_trim(addr);\n}\n\ntypedef struct { char *topic; char *from; long long value; int batch; } logos_net_msg;\ntypedef struct { logos_net_msg *at; long long len, cap; } logos_net_queue;\nstatic logos_net_queue logos_net_outbox, logos_net_received;\nstatic char *logos_net_inbox = NULL;\n\nstatic void logos_net_put(logos_net_queue *q, logos_net_msg m) {\n    if (q->len == q->cap) {\n        q->cap = q->cap ? q->cap * 2 : 8;\n        q->at = (logos_net_msg *)lc_gc_realloc(q->at, (size_t)q->cap * sizeof *q->at);\n    }\n    q->at[q->len++] = m;\n}\n\n/* `Listen on <topic>` \u{2014} `topic` (canonical) becomes this node\'s inbox. */\nvoid logos_net_listen(char *topic) { logos_net_inbox = topic; }\n\n/* `Send`/`Stream` to `topic` (canonical): `how` is 0 for a message, 1 for a batch that is the sequence\n   `value`, 2 for a batch of the one value `value`. */\nvoid logos_net_send(const char *topic, long long value, int how) {\n    if (how == 2) {\n        logos_seq *one = logos_seq_new();\n        logos_seq_push_inplace(one, value);\n        value = (long long)one;\n    }\n    logos_net_msg m = { lc_gc_strdup(topic), lc_gc_strdup(logos_net_inbox ? logos_net_inbox : \"\"), value, how != 0 };\n    logos_net_put(&logos_net_outbox, m);\n}\n\n/* `Await [stream] from <want>` (canonical) \u{2014} the first message (`batch` 0) or batch (`batch` 1) `want` sent to\n   this node\'s inbox. Without an inbox the program stops with `logos_await_without_listen_refusal`. */\nlong long logos_net_await(const char *want, int batch) {\n    if (!logos_net_inbox) logos_fatal(logos_await_without_listen_refusal);\n    for (long long i = 0; i < logos_net_outbox.len; i++) {\n        if (strcmp(logos_net_outbox.at[i].topic, logos_net_inbox) == 0) logos_net_put(&logos_net_received, logos_net_outbox.at[i]);\n    }\n    logos_net_outbox.len = 0;\n    for (long long i = 0; i < logos_net_received.len; i++) {\n        logos_net_msg m = logos_net_received.at[i];\n        if (m.batch == batch && strcmp(m.from, want) == 0) {\n            memmove(&logos_net_received.at[i], &logos_net_received.at[i + 1], (size_t)(logos_net_received.len - i - 1) * sizeof m);\n            logos_net_received.len--;\n            return m.value;\n        }\n    }\n    fflush(stdout);\n    for (;;) pause();\n}\n";
Expand description

logos_show_f64 renders an f64 EXACTLY like the VM’s Show (Rust’s {} Display: shortest decimal that round-trips, NEVER scientific notation, bare integral floats, NaN/inf/-inf/-0). It finds the shortest significant-digit count whose %e form round-trips via strtod, then reformats that to fixed decimal notation so any magnitude prints without an exponent — matching Rust for every finite value. Called with the double in fa0 (a named param, so no variadic-FP marshalling needed).