ludic/selfhost/backend/emit_fence_ir.ludic
Orkuncakilkaya dd20cb2d5d fence: free and realloc stay on the fast path with the arena on - the arena's range checked inline
With the arena running every free and every realloc took the slow path (a call to check the range,
then the fence's own test). Now lp_free checks the arena's range inline and hands anything else to
libc unless the fence is tracking; lp_realloc goes slow only for a scratch request, a tracked run or
an arena block. Ready for when the final run's medians ask for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:37:45 +03:00

1825 lines
76 KiB
Text

# emit_fence_ir.ludic - the allocation fence's runtime (25.1), as IR. Generated from a
# template (docs/plan 25); the tables sized by the program are emit_fence.ludic's.
function emit_fence_globals() -> void {
emith("@lp_site = global i32 0\n")
emith("@lp_want = global i8 0\n")
emith("@lp_ar_on = global i8 0\n")
emith("@lp_ar_tried = global i8 0\n")
emith("@lp_ar_lo = global i64 0\n")
emith("@lp_ar_hi = global i64 0\n")
emith("@lp_ar_cur = global i64 0\n")
emith("@lp_ar_end = global i64 0\n")
emith("@lp_ar_which = global i64 0\n")
emith("@lp_ar_half = global i64 0\n")
emith("@lp_ar_main = global ptr null\n")
emith("@lp_ar_hw0 = global i64 0\n")
emith("@lp_ar_hw1 = global i64 0\n")
emith("@lp_ar_check = global i8 0\n")
emith("@lp_fdecl = global i32 0\n")
emith("@lp_dlive = global i64 0\n")
emith("@lp_mdlive = global i64 0\n")
emith("@lp_sdlive = global i64 0\n")
emith("@lp_ft = global i8 0\n")
emith("@lp_fm = global i8 0\n")
emith("@lp_fj = global i8 0\n")
emith("@lp_fl = global i32 0\n")
emith("@lp_tab = global ptr null\n")
emith("@lp_tabmask = global i64 0\n")
emith("@lp_tabn = global i64 0\n")
emith("@lp_tabmax = global i64 0\n")
emith("@lp_live = global i64 0\n")
emith("@lp_pre = global i64 0\n")
emith("@lp_made = global i64 0\n")
emith("@lp_freed = global i64 0\n")
emith("@lp_over = global i64 0\n")
emith("@lp_overrep = global i8 0\n")
emith("@lp_frame = global i64 0\n")
emith("@lp_flat = global i64 0\n")
emith("@lp_playf = global i64 0\n")
emith("@lp_warm_max = global i64 -1\n")
emith("@lp_fauto = global i8 1\n")
emith("@lp_autoplay = global i64 -1\n")
emith("@lp_mlive = global i64 0\n")
emith("@lp_mpre = global i64 0\n")
emith("@lp_mmade = global i64 0\n")
emith("@lp_mfreed = global i64 0\n")
emith("@lp_slive = global i64 0\n")
emith("@lp_spre = global i64 0\n")
emith("@lp_touch = global [512 x i32] zeroinitializer\n")
emith("@lp_ntouch = global i32 0\n")
emith("@lp_fkept = global i64 0\n")
emith("@lp_fbad = global i64 0\n")
emith("@lp_fjudged = global i64 0\n")
emith("@lp_scan_at = global i64 -2\n")
emith("@lp_visit_set = global ptr null\n")
emith("@lp_vmask = global i64 0\n")
emith("@lp_wl = global ptr null\n")
emith("@lp_wln = global i64 0\n")
emith("@lp_wlcap = global i64 0\n")
emith("@lp_scan_bytes = global i64 0\n")
emith("@lp_capn = global i64 0\n")
emith("@lp_zset = global i64 0\n")
emith("@lp_jset = global i64 0\n")
emith("@lp_vset = global i64 0\n")
emith("@lp_census = global ptr null\n")
emith("declare extern_weak i64 @malloc_size(ptr)\n")
emith("declare i32 @dprintf(i32, ptr, ...)\n")
emith("declare i32 @_Unwind_Backtrace(ptr, ptr)\n")
emith("declare i64 @_Unwind_GetIP(ptr)\n")
emith("declare i32 @dladdr(ptr, ptr)\n")
emith("declare ptr @dlsym(ptr, ptr)\n")
emith("declare ptr @pthread_self()\n")
emith("@.lpf_env = private unnamed_addr constant [16 x i8] c\"R3D_ALLOC_FENCE\\00\"\n")
emith("@.lpf_warm = private unnamed_addr constant [15 x i8] c\"R3D_ALLOC_WARM\\00\"\n")
emith("@.lpf_play = private unnamed_addr constant [15 x i8] c\"R3D_ALLOC_PLAY\\00\"\n")
emith("@.lpf_tab = private unnamed_addr constant [16 x i8] c\"R3D_ALLOC_TABLE\\00\"\n")
emith("@.lpf_dev = private unnamed_addr constant [8 x i8] c\"R3D_DEV\\00\"\n")
emith("@.lpf_off = private unnamed_addr constant [4 x i8] c\"off\\00\"\n")
emith("@.lpf_count = private unnamed_addr constant [6 x i8] c\"count\\00\"\n")
emith("@.lpf_warn = private unnamed_addr constant [5 x i8] c\"warn\\00\"\n")
emith("@.lpf_fail = private unnamed_addr constant [5 x i8] c\"fail\\00\"\n")
emith("@.lpf_hdr = private unnamed_addr constant [62 x i8] c\"alloc-fence: frame %lld kept %+lld B (%lld made, %lld freed)\\0A\\00\"\n")
emith("@.lpf_row = private unnamed_addr constant [26 x i8] c\" %+lld B %s %s:%d %s\\0A\\00\"\n")
emith("@.lpf_more = private unnamed_addr constant [21 x i8] c\" ... and %lld more\\0A\\00\"\n")
emith("@.lpf_full = private unnamed_addr constant [71 x i8] c\"alloc-fence: %s is full - it stops keeping and makes a copy each time\\0A\\00\"\n")
emith("@.lpf_arena = private unnamed_addr constant [10 x i8] c\"R3D_ARENA\\00\"\n")
emith("@.lpf_arenamb = private unnamed_addr constant [13 x i8] c\"R3D_ARENA_MB\\00\"\n")
emith("@.lpf_archeck = private unnamed_addr constant [16 x i8] c\"R3D_ARENA_CHECK\\00\"\n")
emith("@.lpf_car = private unnamed_addr constant [61 x i8] c\"arena %lld %lld (each frame arena's high-water mark, bytes)\\0A\\00\"\n")
emith("@.lpf_capover = private unnamed_addr constant [54 x i8] c\"alloc-fence: %s grew past its @max(%d) (it holds %d)\\0A\\00\"\n")
emith("@.lpf_capfail = private unnamed_addr constant [78 x i8] c\"alloc-fence: failing the run (R3D_ALLOC_FENCE=fail): a capacity is a promise\\0A\\00\"\n")
emith("@.lpf_ccap = private unnamed_addr constant [56 x i8] c\"overflows %lld (a list past its @max, or a table full)\\0A\\00\"\n")
emith("@.lpf_scan = private unnamed_addr constant [15 x i8] c\"R3D_ALLOC_SCAN\\00\"\n")
emith("@.lpf_scantop = private unnamed_addr constant [19 x i8] c\"R3D_ALLOC_SCAN_TOP\\00\"\n")
emith("@.lpf_scanfile = private unnamed_addr constant [20 x i8] c\"R3D_ALLOC_SCAN_FILE\\00\"\n")
emith("@.lpf_sfrow = private unnamed_addr constant [18 x i8] c\"%lld %s %s:%d %s\\0A\\00\"\n")
emith("@.lpf_a = private unnamed_addr constant [2 x i8] c\"a\\00\"\n")
emith("@.lpf_exitscan = private unnamed_addr constant [15 x i8] c\"R3D_ALLOC_EXIT\\00\"\n")
emith("@.lpf_shdr = private unnamed_addr constant [116 x i8] c\"alloc-scan: frame %lld - %lld bytes in %lld blocks made since tracking began are reachable from no global or state\\0A\\00\"\n")
emith("@.lpf_srow = private unnamed_addr constant [25 x i8] c\" %lld B %s %s:%d %s\\0A\\00\"\n")
emith("@.lpf_cown = private unnamed_addr constant [49 x i8] c\"owner %s holds %lld (%+lld since judging began)\\0A\\00\"\n")
emith("@.lpf_failing = private unnamed_addr constant [53 x i8] c\"alloc-fence: failing the run (R3D_ALLOC_FENCE=fail)\\0A\\00\"\n")
emith("@.lpf_census = private unnamed_addr constant [17 x i8] c\"R3D_ALLOC_CENSUS\\00\"\n")
emith("@.lpf_warmmax = private unnamed_addr constant [19 x i8] c\"R3D_ALLOC_WARM_MAX\\00\"\n")
emith("@.lpf_auto = private unnamed_addr constant [15 x i8] c\"R3D_ALLOC_AUTO\\00\"\n")
emith("@.lpf_w = private unnamed_addr constant [2 x i8] c\"w\\00\"\n")
emith("@.lpf_chdr = private unnamed_addr constant [76 x i8] c\"alloc-census frames %lld bad %lld kept %lld made %lld freed %lld over %lld\\0A\\00\"\n")
emith("@.lpf_cnat = private unnamed_addr constant [116 x i8] c\"native %lld (the heap outside Ludic's blocks and the counted libraries, since judging began: drivers, Metal, libc)\\0A\\00\"\n")
emith("@.lpf_cdecl = private unnamed_addr constant [58 x i8] c\"declared %lld (kept under @alloc_ok since judging began)\\0A\\00\"\n")
emith("@.lpf_cjolt = private unnamed_addr constant [68 x i8] c\"jolt %lld peak %lld (since judging began, and its high-water mark)\\0A\\00\"\n")
emith("@.lpf_cvk = private unnamed_addr constant [83 x i8] c\"vulkan %lld peak %lld (host memory through VkAllocationCallbacks, R3D_ALLOC_VK=1)\\0A\\00\"\n")
emith("@.lpf_jb = private unnamed_addr constant [15 x i8] c\"jph_heap_bytes\\00\"\n")
emith("@.lpf_jp = private unnamed_addr constant [14 x i8] c\"jph_heap_peak\\00\"\n")
emith("@.lpf_vb = private unnamed_addr constant [13 x i8] c\"lvk_ac_bytes\\00\"\n")
emith("@.lpf_vp = private unnamed_addr constant [12 x i8] c\"lvk_ac_peak\\00\"\n")
emith("@.lpf_crow = private unnamed_addr constant [23 x i8] c\"site %lld %s %s:%d %s\\0A\\00\"\n")
emith("@.lpf_from = private unnamed_addr constant [15 x i8] c\" from %s\\0A\\00\"\n")
emith("@.lpf_cfrom = private unnamed_addr constant [11 x i8] c\" from %s\\0A\\00\"\n")
emith("@.lpf_lp = private unnamed_addr constant [4 x i8] c\"lp_\\00\"\n")
}
function emit_fence_entry() -> void {
emith("; the four entry points. Off: one load of the fence and the scratch request, one branch, then libc.\n")
emith("; @lp_want is raised by the emitter around an allocation of a LOCAL site (25.3): it goes to the\n")
emith("; frame's scratch arena, and lp_free hands an arena block back to nobody\n")
emith("define internal ptr @lp_heap(i64 %n) {\n")
emith("entry:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %on = icmp ne i8 %t, 0\n")
emith(" br i1 %on, label %slow, label %fast\n")
emith("fast:\n")
emith(" %p = tail call ptr @malloc(i64 %n)\n")
emith(" ret ptr %p\n")
emith("slow:\n")
emith(" %q = call ptr @malloc(i64 %n)\n")
emith(" call void @lp_fadd(ptr %q, i64 %n)\n")
emith(" ret ptr %q\n")
emith("}\n")
emith("define ptr @lp_malloc(i64 %n) {\n")
emith("entry:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %w = load i8, ptr @lp_want\n")
emith(" %o = or i8 %t, %w\n")
emith(" %on = icmp ne i8 %o, 0\n")
emith(" br i1 %on, label %slow, label %fast\n")
emith("fast:\n")
emith(" %p = tail call ptr @malloc(i64 %n)\n")
emith(" ret ptr %p\n")
emith("slow:\n")
emith(" %wq = icmp ne i8 %w, 0\n")
emith(" br i1 %wq, label %scratch, label %heap\n")
emith("scratch:\n")
emith(" store i8 0, ptr @lp_want\n")
emith(" %s = call ptr @lp_scratch(i64 %n)\n")
emith(" ret ptr %s\n")
emith("heap:\n")
emith(" %q = call ptr @malloc(i64 %n)\n")
emith(" call void @lp_fadd(ptr %q, i64 %n)\n")
emith(" ret ptr %q\n")
emith("}\n")
emith("define ptr @lp_calloc(i64 %n, i64 %s) {\n")
emith("entry:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %w = load i8, ptr @lp_want\n")
emith(" %o = or i8 %t, %w\n")
emith(" %on = icmp ne i8 %o, 0\n")
emith(" br i1 %on, label %slow, label %fast\n")
emith("fast:\n")
emith(" %p = tail call ptr @calloc(i64 %n, i64 %s)\n")
emith(" ret ptr %p\n")
emith("slow:\n")
emith(" %b = mul i64 %n, %s\n")
emith(" %wq = icmp ne i8 %w, 0\n")
emith(" br i1 %wq, label %scratch, label %heap\n")
emith("scratch:\n")
emith(" store i8 0, ptr @lp_want\n")
emith(" %z = call ptr @lp_scratch(i64 %b)\n")
emith(" call ptr @memset(ptr %z, i32 0, i64 %b)\n")
emith(" ret ptr %z\n")
emith("heap:\n")
emith(" %q = call ptr @calloc(i64 %n, i64 %s)\n")
emith(" call void @lp_fadd(ptr %q, i64 %b)\n")
emith(" ret ptr %q\n")
emith("}\n")
emith("define ptr @lp_realloc(ptr %o, i64 %n) {\n")
emith("entry:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %w = load i8, ptr @lp_want\n")
emith(" %x = ptrtoint ptr %o to i64\n")
emith(" %lo = load i64, ptr @lp_ar_lo\n")
emith(" %hi = load i64, ptr @lp_ar_hi\n")
emith(" %ge = icmp uge i64 %x, %lo\n")
emith(" %lt = icmp ult i64 %x, %hi\n")
emith(" %inar = and i1 %ge, %lt\n")
emith(" %o1 = or i8 %t, %w\n")
emith(" %some = icmp ne i8 %o1, 0\n")
emith(" %on = or i1 %some, %inar\n")
emith(" br i1 %on, label %slow, label %fast\n")
emith("fast:\n")
emith(" %p = tail call ptr @realloc(ptr %o, i64 %n)\n")
emith(" ret ptr %p\n")
emith("slow:\n")
emith(" %in = call i1 @lp_in_arena(ptr %o)\n")
emith(" %wq = icmp ne i8 %w, 0\n")
emith(" %move = or i1 %in, %wq\n")
emith(" br i1 %move, label %scratch, label %heap\n")
emith("scratch:\n")
emith(" store i8 0, ptr @lp_want\n")
emith(" %q = call ptr @lp_scratch(i64 %n)\n")
emith(" %none = icmp eq ptr %o, null\n")
emith(" br i1 %none, label %done, label %copy\n")
emith("copy:\n")
emith(" br i1 %in, label %oldar, label %oldheap\n")
emith("oldar:\n")
emith(" %hp = getelementptr i8, ptr %o, i64 -16\n")
emith(" %osz = load i64, ptr %hp\n")
emith(" br label %cp\n")
emith("oldheap:\n")
emith(" %has = icmp ne ptr @malloc_size, null\n")
emith(" br i1 %has, label %msz, label %cp\n")
emith("msz:\n")
emith(" %hsz = call i64 @malloc_size(ptr %o)\n")
emith(" br label %cp\n")
emith("cp:\n")
emith(" %old = phi i64 [ %osz, %oldar ], [ 0, %oldheap ], [ %hsz, %msz ]\n")
emith(" %less = icmp ult i64 %old, %n\n")
emith(" %c = select i1 %less, i64 %old, i64 %n\n")
emith(" call ptr @memcpy(ptr %q, ptr %o, i64 %c)\n")
emith(" br i1 %in, label %done, label %givebk\n")
emith("givebk:\n")
emith(" call void @lp_free(ptr %o)\n")
emith(" br label %done\n")
emith("done:\n")
emith(" ret ptr %q\n")
emith("heap:\n")
emith(" %tq = icmp ne i8 %t, 0\n")
emith(" br i1 %tq, label %tracked, label %plain\n")
emith("plain:\n")
emith(" %r = tail call ptr @realloc(ptr %o, i64 %n)\n")
emith(" ret ptr %r\n")
emith("tracked:\n")
emith(" call void @lp_fdel(ptr %o)\n")
emith(" %r2 = call ptr @realloc(ptr %o, i64 %n)\n")
emith(" call void @lp_fadd(ptr %r2, i64 %n)\n")
emith(" ret ptr %r2\n")
emith("}\n")
emith("define void @lp_free(ptr %o) {\n")
emith("entry:\n")
emith(" %x = ptrtoint ptr %o to i64\n")
emith(" %lo = load i64, ptr @lp_ar_lo\n")
emith(" %hi = load i64, ptr @lp_ar_hi\n")
emith(" %ge = icmp uge i64 %x, %lo\n")
emith(" %lt = icmp ult i64 %x, %hi\n")
emith(" %in = and i1 %ge, %lt\n")
emith(" br i1 %in, label %keep, label %heap\n")
emith("keep:\n")
emith(" ret void\n")
emith("heap:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %tq = icmp ne i8 %t, 0\n")
emith(" br i1 %tq, label %tracked, label %plain\n")
emith("plain:\n")
emith(" tail call void @free(ptr %o)\n")
emith(" ret void\n")
emith("tracked:\n")
emith(" call void @lp_fdel(ptr %o)\n")
emith(" call void @free(ptr %o)\n")
emith(" ret void\n")
emith("}\n")
emith("define internal i1 @lp_in_arena(ptr %o) {\n")
emith("entry:\n")
emith(" %x = ptrtoint ptr %o to i64\n")
emith(" %lo = load i64, ptr @lp_ar_lo\n")
emith(" %hi = load i64, ptr @lp_ar_hi\n")
emith(" %a = icmp uge i64 %x, %lo\n")
emith(" %b = icmp ult i64 %x, %hi\n")
emith(" %in = and i1 %a, %b\n")
emith(" ret i1 %in\n")
emith("}\n")
emith("; a block from the frame's arena: a 16-byte header (its size) and 16-aligned; the heap when no\n")
emith("; frame is running, off the main thread, or past the arena's end\n")
emith("define internal ptr @lp_scratch(i64 %n) {\n")
emith("entry:\n")
emith(" %on = load i8, ptr @lp_ar_on\n")
emith(" %onq = icmp ne i8 %on, 0\n")
emith(" br i1 %onq, label %thread, label %heap\n")
emith("thread:\n")
emith(" %me = call ptr @pthread_self()\n")
emith(" %main = load ptr, ptr @lp_ar_main\n")
emith(" %mainq = icmp eq ptr %me, %main\n")
emith(" br i1 %mainq, label %bump, label %heap\n")
emith("bump:\n")
emith(" %cur = load i64, ptr @lp_ar_cur\n")
emith(" %n16 = add i64 %n, 31\n")
emith(" %need = and i64 %n16, -16\n")
emith(" %np = add i64 %cur, %need\n")
emith(" %end = load i64, ptr @lp_ar_end\n")
emith(" %fits = icmp ule i64 %np, %end\n")
emith(" br i1 %fits, label %take, label %heap\n")
emith("take:\n")
emith(" store i64 %np, ptr @lp_ar_cur\n")
emith(" %hp = inttoptr i64 %cur to ptr\n")
emith(" store i64 %n, ptr %hp\n")
emith(" %bp = getelementptr i8, ptr %hp, i64 16\n")
emith(" ret ptr %bp\n")
emith("heap:\n")
emith(" %h = call ptr @lp_heap(i64 %n)\n")
emith(" ret ptr %h\n")
emith("}\n")
emith("; the frame's mark for the arenas: the first reserves them (two halves, R3D_ARENA_MB each, 256 by\n")
emith("; default; R3D_ARENA=0 keeps everything on the heap), then each flips to the other half - which\n")
emith("; held the frame before last - and starts it again (R3D_ARENA_CHECK=1 fills it with 0xDD first)\n")
emith("define internal void @lp_ar_frame() {\n")
emith("entry:\n")
emith(" %def = load i8, ptr @lp_ardef\n")
emith(" %defq = icmp ne i8 %def, 0\n")
emith(" br i1 %defq, label %chk, label %out\n")
emith("chk:\n")
emith(" %on = load i8, ptr @lp_ar_on\n")
emith(" %onq = icmp ne i8 %on, 0\n")
emith(" br i1 %onq, label %flip, label %maybe\n")
emith("maybe:\n")
emith(" %tried = load i8, ptr @lp_ar_tried\n")
emith(" %tq = icmp ne i8 %tried, 0\n")
emith(" br i1 %tq, label %out, label %reserve\n")
emith("reserve:\n")
emith(" store i8 1, ptr @lp_ar_tried\n")
emith(" %want = call i64 @lp_fenv(ptr @.lpf_arena, i64 1)\n")
emith(" %wz = icmp eq i64 %want, 0\n")
emith(" br i1 %wz, label %out, label %size\n")
emith("size:\n")
emith(" %mb = call i64 @lp_fenv(ptr @.lpf_arenamb, i64 256)\n")
emith(" %half = shl i64 %mb, 20\n")
emith(" store i64 %half, ptr @lp_ar_half\n")
emith(" %both = shl i64 %half, 1\n")
emith(" %m = call ptr @mmap(ptr null, i64 %both, i32 3, i32 4098, i32 -1, i64 0)\n")
emith(" %mi = ptrtoint ptr %m to i64\n")
emith(" %bad = icmp eq i64 %mi, -1\n")
emith(" br i1 %bad, label %out, label %armed\n")
emith("armed:\n")
emith(" store i64 %mi, ptr @lp_ar_lo\n")
emith(" %hi = add i64 %mi, %both\n")
emith(" store i64 %hi, ptr @lp_ar_hi\n")
emith(" store i64 %mi, ptr @lp_ar_cur\n")
emith(" %e0 = add i64 %mi, %half\n")
emith(" store i64 %e0, ptr @lp_ar_end\n")
emith(" store i64 0, ptr @lp_ar_which\n")
emith(" %me = call ptr @pthread_self()\n")
emith(" store ptr %me, ptr @lp_ar_main\n")
emith(" %ck = call i64 @lp_fenv(ptr @.lpf_archeck, i64 0)\n")
emith(" %ck8 = trunc i64 %ck to i8\n")
emith(" store i8 %ck8, ptr @lp_ar_check\n")
emith(" store i8 1, ptr @lp_ar_on\n")
emith(" br label %out\n")
emith("flip:\n")
emith(" %w = load i64, ptr @lp_ar_which\n")
emith(" %lo = load i64, ptr @lp_ar_lo\n")
emith(" %hf = load i64, ptr @lp_ar_half\n")
emith(" %off = mul i64 %w, %hf\n")
emith(" %start = add i64 %lo, %off\n")
emith(" %cur = load i64, ptr @lp_ar_cur\n")
emith(" %used = sub i64 %cur, %start\n")
emith(" %w0 = icmp eq i64 %w, 0\n")
emith(" %hwq = select i1 %w0, ptr @lp_ar_hw0, ptr @lp_ar_hw1\n")
emith(" %hwv = load i64, ptr %hwq\n")
emith(" %more = icmp ugt i64 %used, %hwv\n")
emith(" %hwn = select i1 %more, i64 %used, i64 %hwv\n")
emith(" store i64 %hwn, ptr %hwq\n")
emith(" %nw = xor i64 %w, 1\n")
emith(" store i64 %nw, ptr @lp_ar_which\n")
emith(" %noff = mul i64 %nw, %hf\n")
emith(" %nstart = add i64 %lo, %noff\n")
emith(" store i64 %nstart, ptr @lp_ar_cur\n")
emith(" %nend = add i64 %nstart, %hf\n")
emith(" store i64 %nend, ptr @lp_ar_end\n")
emith(" %cq = load i8, ptr @lp_ar_check\n")
emith(" %cqq = icmp ne i8 %cq, 0\n")
emith(" br i1 %cqq, label %poison, label %out\n")
emith("poison:\n")
emith(" %n0 = icmp eq i64 %nw, 0\n")
emith(" %nhq = select i1 %n0, ptr @lp_ar_hw0, ptr @lp_ar_hw1\n")
emith(" %nhv = load i64, ptr %nhq\n")
emith(" %np = inttoptr i64 %nstart to ptr\n")
emith(" call ptr @memset(ptr %np, i32 221, i64 %nhv)\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
}
function emit_fence_table() -> void {
emith("define internal void @lp_flock() {\n")
emith("entry:\n")
emith(" br label %spin\n")
emith("spin:\n")
emith(" %o = atomicrmw xchg ptr @lp_fl, i32 1 acquire\n")
emith(" %b = icmp eq i32 %o, 0\n")
emith(" br i1 %b, label %done, label %spin\n")
emith("done:\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_funlock() {\n")
emith("entry:\n")
emith(" store atomic i32 0, ptr @lp_fl release, align 4\n")
emith(" ret void\n")
emith("}\n")
emith("define internal i64 @lp_fhash(i64 %k) {\n")
emith("entry:\n")
emith(" %a = lshr i64 %k, 4\n")
emith(" %b = mul i64 %a, -7046029254386353131\n")
emith(" %c = lshr i64 %b, 29\n")
emith(" %d = xor i64 %b, %c\n")
emith(" ret i64 %d\n")
emith("}\n")
emith("define internal void @lp_ftouch(i64 %s) {\n")
emith("entry:\n")
emith(" %sp = getelementptr inbounds i64, ptr @lp_site_stamp, i64 %s\n")
emith(" %st = load i64, ptr %sp\n")
emith(" %f = load i64, ptr @lp_frame\n")
emith(" %f1 = add i64 %f, 1\n")
emith(" %seen = icmp eq i64 %st, %f1\n")
emith(" br i1 %seen, label %out, label %mark\n")
emith("mark:\n")
emith(" store i64 %f1, ptr %sp\n")
emith(" %n = load i32, ptr @lp_ntouch\n")
emith(" %room = icmp ult i32 %n, 512\n")
emith(" %n1 = add i32 %n, 1\n")
emith(" store i32 %n1, ptr @lp_ntouch\n")
emith(" br i1 %room, label %put, label %out\n")
emith("put:\n")
emith(" %tp = getelementptr inbounds [512 x i32], ptr @lp_touch, i32 0, i32 %n\n")
emith(" %s32 = trunc i64 %s to i32\n")
emith(" store i32 %s32, ptr %tp\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_fsite_dadd(i64 %s, i64 %n) {\n")
emith("entry:\n")
emith(" %sp = getelementptr inbounds i64, ptr @lp_site_dlive, i64 %s\n")
emith(" %v = load i64, ptr %sp\n")
emith(" %v1 = add i64 %v, %n\n")
emith(" store i64 %v1, ptr %sp\n")
emith(" %dl = load i64, ptr @lp_dlive\n")
emith(" %dl1 = add i64 %dl, %n\n")
emith(" store i64 %dl1, ptr @lp_dlive\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_fsite_add(i64 %s, i64 %n) {\n")
emith("entry:\n")
emith(" %sp = getelementptr inbounds i64, ptr @lp_site_live, i64 %s\n")
emith(" %v = load i64, ptr %sp\n")
emith(" %v1 = add i64 %v, %n\n")
emith(" store i64 %v1, ptr %sp\n")
emith(" %lv = load i64, ptr @lp_live\n")
emith(" %lv1 = add i64 %lv, %n\n")
emith(" store i64 %lv1, ptr @lp_live\n")
emith(" call void @lp_ftouch(i64 %s)\n")
emith(" ret void\n")
emith("}\n")
emith("; the last six return addresses above an allocation of site s, from the unwinder (the emitted\n")
emith("; functions keep no frame-pointer chain), taken only once judging has begun: what is made then is\n")
emith("; what a report names, and it is rare\n")
emith("define internal i32 @lp_funw(ptr %ctx, ptr %st) {\n")
emith("entry:\n")
emith(" %n = load i64, ptr %st\n")
emith(" %full = icmp uge i64 %n, 6\n")
emith(" br i1 %full, label %stop, label %take\n")
emith("take:\n")
emith(" %ip = call i64 @_Unwind_GetIP(ptr %ctx)\n")
emith(" %bp = getelementptr inbounds i64, ptr %st, i64 1\n")
emith(" %base = load i64, ptr %bp\n")
emith(" %slot = add i64 %base, %n\n")
emith(" %dst = getelementptr inbounds i64, ptr @lp_site_ra, i64 %slot\n")
emith(" store i64 %ip, ptr %dst\n")
emith(" %n1 = add i64 %n, 1\n")
emith(" store i64 %n1, ptr %st\n")
emith(" ret i32 0\n")
emith("stop:\n")
emith(" ret i32 5\n")
emith("}\n")
emith("define internal void @lp_fcallers(i64 %s) noinline {\n")
emith("entry:\n")
emith(" %j = load i8, ptr @lp_fj\n")
emith(" %judging = icmp ne i8 %j, 0\n")
emith(" br i1 %judging, label %walk, label %out\n")
emith("walk:\n")
emith(" %st = alloca [2 x i64], align 8\n")
emith(" store i64 0, ptr %st\n")
emith(" %bp = getelementptr inbounds i64, ptr %st, i64 1\n")
emith(" %base = mul i64 %s, 6\n")
emith(" store i64 %base, ptr %bp\n")
emith(" %z = getelementptr inbounds i64, ptr @lp_site_ra, i64 %base\n")
emith(" call ptr @memset(ptr %z, i32 0, i64 48)\n")
emith(" call i32 @_Unwind_Backtrace(ptr @lp_funw, ptr %st)\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("; the Ludic functions a site was last reached from: its callers' names, those of the fence and of\n")
emith("; the site's own function left out\n")
emith("define internal void @lp_fsite_from(ptr %fp, i32 %s, ptr %own) {\n")
emith("entry:\n")
emith(" %info = alloca [4 x ptr], align 8\n")
emith(" %s64 = sext i32 %s to i64\n")
emith(" %base = mul i64 %s64, 6\n")
emith(" br label %loop\n")
emith("loop:\n")
emith(" %i = phi i64 [ 0, %entry ], [ %i1, %next ]\n")
emith(" %shown = phi i32 [ 0, %entry ], [ %shown1, %next ]\n")
emith(" %more = icmp ult i64 %i, 6\n")
emith(" %room = icmp ult i32 %shown, 3\n")
emith(" %go = and i1 %more, %room\n")
emith(" br i1 %go, label %body, label %out\n")
emith("body:\n")
emith(" %slot = add i64 %base, %i\n")
emith(" %rp = getelementptr inbounds ptr, ptr @lp_site_ra, i64 %slot\n")
emith(" %ra0 = load ptr, ptr %rp\n")
emith(" %ra = getelementptr i8, ptr %ra0, i64 -1\n")
emith(" %nul = icmp eq ptr %ra0, null\n")
emith(" br i1 %nul, label %skip, label %look\n")
emith("look:\n")
emith(" %ok = call i32 @dladdr(ptr %ra, ptr %info)\n")
emith(" %okq = icmp ne i32 %ok, 0\n")
emith(" br i1 %okq, label %named, label %skip\n")
emith("named:\n")
emith(" %snp = getelementptr inbounds [4 x ptr], ptr %info, i32 0, i32 2\n")
emith(" %sn = load ptr, ptr %snp\n")
emith(" %snnul = icmp eq ptr %sn, null\n")
emith(" br i1 %snnul, label %skip, label %filter\n")
emith("filter:\n")
emith(" %c1 = call i32 @strncmp(ptr %sn, ptr @.lpf_lp, i64 3)\n")
emith(" %islp = icmp eq i32 %c1, 0\n")
emith(" %own3 = getelementptr inbounds i8, ptr %sn, i64 3\n")
emith(" %c2 = call i32 @strcmp(ptr %own3, ptr %own)\n")
emith(" %isown = icmp eq i32 %c2, 0\n")
emith(" %drop = or i1 %islp, %isown\n")
emith(" br i1 %drop, label %skip, label %print\n")
emith("print:\n")
emith(" %tofile = icmp ne ptr %fp, null\n")
emith(" br i1 %tofile, label %pf, label %pe\n")
emith("pf:\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_cfrom, ptr %sn)\n")
emith(" br label %counted\n")
emith("pe:\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_from, ptr %sn)\n")
emith(" br label %counted\n")
emith("counted:\n")
emith(" br label %next\n")
emith("skip:\n")
emith(" br label %next\n")
emith("next:\n")
emith(" %add = phi i32 [ 1, %counted ], [ 0, %skip ]\n")
emith(" %shown1 = add i32 %shown, %add\n")
emith(" %i1 = add i64 %i, 1\n")
emith(" br label %loop\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_fadd(ptr %p, i64 %asked) {\n")
emith("entry:\n")
emith(" %isnull = icmp eq ptr %p, null\n")
emith(" br i1 %isnull, label %out, label %size\n")
emith("size:\n")
emith(" %hasms = icmp ne ptr @malloc_size, null\n")
emith(" br i1 %hasms, label %real, label %go\n")
emith("real:\n")
emith(" %ms = call i64 @malloc_size(ptr %p)\n")
emith(" br label %go\n")
emith("go:\n")
emith(" %n = phi i64 [ %asked, %size ], [ %ms, %real ]\n")
emith(" call void @lp_flock()\n")
emith(" %cnt = load i64, ptr @lp_tabn\n")
emith(" %max = load i64, ptr @lp_tabmax\n")
emith(" %full = icmp sge i64 %cnt, %max\n")
emith(" br i1 %full, label %over, label %ins\n")
emith("over:\n")
emith(" %ov = load i64, ptr @lp_over\n")
emith(" %ov1 = add i64 %ov, 1\n")
emith(" store i64 %ov1, ptr @lp_over\n")
emith(" br label %unlock\n")
emith("ins:\n")
emith(" %s0 = load i32, ptr @lp_site\n")
emith(" %sn = load i32, ptr @lp_site_n\n")
emith(" %sok = icmp ult i32 %s0, %sn\n")
emith(" %s = select i1 %sok, i32 %s0, i32 0\n")
emith(" %s64 = zext i32 %s to i64\n")
emith(" %k = ptrtoint ptr %p to i64\n")
emith(" %h = call i64 @lp_fhash(i64 %k)\n")
emith(" %mask = load i64, ptr @lp_tabmask\n")
emith(" %tab = load ptr, ptr @lp_tab\n")
emith(" br label %probe\n")
emith("probe:\n")
emith(" %i = phi i64 [ %h, %ins ], [ %i1, %next ]\n")
emith(" %im = and i64 %i, %mask\n")
emith(" %e = getelementptr inbounds [2 x i64], ptr %tab, i64 %im\n")
emith(" %ek = load i64, ptr %e\n")
emith(" %empty = icmp eq i64 %ek, 0\n")
emith(" br i1 %empty, label %put, label %chk\n")
emith("chk:\n")
emith(" %same = icmp eq i64 %ek, %k\n")
emith(" br i1 %same, label %dup, label %next\n")
emith("next:\n")
emith(" %i1 = add i64 %im, 1\n")
emith(" br label %probe\n")
emith("dup:\n")
emith(" %dv = getelementptr inbounds i64, ptr %e, i64 1\n")
emith(" %dold = load i64, ptr %dv\n")
emith(" %dn = and i64 %dold, 549755813887\n")
emith(" %ds = lshr i64 %dold, 40\n")
emith(" %dneg = sub i64 0, %dn\n")
emith(" %dwd = and i64 %dold, 549755813888\n")
emith(" %dwas = icmp ne i64 %dwd, 0\n")
emith(" br i1 %dwas, label %ddecl, label %dund\n")
emith("ddecl:\n")
emith(" call void @lp_fsite_dadd(i64 %ds, i64 %dneg)\n")
emith(" br label %dcount\n")
emith("dund:\n")
emith(" call void @lp_fsite_add(i64 %ds, i64 %dneg)\n")
emith(" br label %dcount\n")
emith("dcount:\n")
emith(" %dtn = load i64, ptr @lp_tabn\n")
emith(" %dtn1 = sub i64 %dtn, 1\n")
emith(" store i64 %dtn1, ptr @lp_tabn\n")
emith(" %dfr = load i64, ptr @lp_freed\n")
emith(" %dfr1 = add i64 %dfr, 1\n")
emith(" store i64 %dfr1, ptr @lp_freed\n")
emith(" br label %put\n")
emith("put:\n")
emith(" store i64 %k, ptr %e\n")
emith(" %ev = getelementptr inbounds i64, ptr %e, i64 1\n")
emith(" %sh = shl i64 %s64, 40\n")
emith(" %v0 = or i64 %sh, %n\n")
emith(" %dc = load i32, ptr @lp_fdecl\n")
emith(" %isdecl = icmp sgt i32 %dc, 0\n")
emith(" %dbit = select i1 %isdecl, i64 549755813888, i64 0\n")
emith(" %v = or i64 %v0, %dbit\n")
emith(" store i64 %v, ptr %ev\n")
emith(" %tn = load i64, ptr @lp_tabn\n")
emith(" %tn1 = add i64 %tn, 1\n")
emith(" store i64 %tn1, ptr @lp_tabn\n")
emith(" %md = load i64, ptr @lp_made\n")
emith(" %md1 = add i64 %md, 1\n")
emith(" store i64 %md1, ptr @lp_made\n")
emith(" br i1 %isdecl, label %pdecl, label %pund\n")
emith("pdecl:\n")
emith(" call void @lp_fsite_dadd(i64 %s64, i64 %n)\n")
emith(" br label %unlock\n")
emith("pund:\n")
emith(" call void @lp_fsite_add(i64 %s64, i64 %n)\n")
emith(" call void @lp_fcallers(i64 %s64)\n")
emith(" br label %unlock\n")
emith("unlock:\n")
emith(" call void @lp_funlock()\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_fdel(ptr %p) {\n")
emith("entry:\n")
emith(" %isnull = icmp eq ptr %p, null\n")
emith(" br i1 %isnull, label %out, label %go\n")
emith("go:\n")
emith(" call void @lp_flock()\n")
emith(" %k = ptrtoint ptr %p to i64\n")
emith(" %h = call i64 @lp_fhash(i64 %k)\n")
emith(" %mask = load i64, ptr @lp_tabmask\n")
emith(" %tab = load ptr, ptr @lp_tab\n")
emith(" br label %probe\n")
emith("probe:\n")
emith(" %i = phi i64 [ %h, %go ], [ %i1, %next ]\n")
emith(" %im = and i64 %i, %mask\n")
emith(" %e = getelementptr inbounds [2 x i64], ptr %tab, i64 %im\n")
emith(" %ek = load i64, ptr %e\n")
emith(" %empty = icmp eq i64 %ek, 0\n")
emith(" br i1 %empty, label %miss, label %cmp\n")
emith("cmp:\n")
emith(" %hit = icmp eq i64 %ek, %k\n")
emith(" br i1 %hit, label %found, label %next\n")
emith("next:\n")
emith(" %i1 = add i64 %im, 1\n")
emith(" br label %probe\n")
emith("miss:\n")
emith(" %has = icmp ne ptr @malloc_size, null\n")
emith(" br i1 %has, label %msz, label %unlock\n")
emith("msz:\n")
emith(" %ms = call i64 @malloc_size(ptr %p)\n")
emith(" %pr = load i64, ptr @lp_pre\n")
emith(" %pr1 = add i64 %pr, %ms\n")
emith(" store i64 %pr1, ptr @lp_pre\n")
emith(" br label %unlock\n")
emith("found:\n")
emith(" %ev = getelementptr inbounds i64, ptr %e, i64 1\n")
emith(" %v = load i64, ptr %ev\n")
emith(" %n = and i64 %v, 549755813887\n")
emith(" %s = lshr i64 %v, 40\n")
emith(" %neg = sub i64 0, %n\n")
emith(" %wd = and i64 %v, 549755813888\n")
emith(" %wasdecl = icmp ne i64 %wd, 0\n")
emith(" br i1 %wasdecl, label %fdecl, label %fund\n")
emith("fdecl:\n")
emith(" call void @lp_fsite_dadd(i64 %s, i64 %neg)\n")
emith(" br label %fcount\n")
emith("fund:\n")
emith(" call void @lp_fsite_add(i64 %s, i64 %neg)\n")
emith(" br label %fcount\n")
emith("fcount:\n")
emith(" %fr = load i64, ptr @lp_freed\n")
emith(" %fr1 = add i64 %fr, 1\n")
emith(" store i64 %fr1, ptr @lp_freed\n")
emith(" %tn = load i64, ptr @lp_tabn\n")
emith(" %tn1 = sub i64 %tn, 1\n")
emith(" store i64 %tn1, ptr @lp_tabn\n")
emith(" br label %sh\n")
emith("sh:\n")
emith(" %hole = phi i64 [ %im, %fcount ], [ %hole, %sh_skip ], [ %j, %sh_move ]\n")
emith(" %jp = phi i64 [ %im, %fcount ], [ %j, %sh_skip ], [ %j, %sh_move ]\n")
emith(" %j0 = add i64 %jp, 1\n")
emith(" %j = and i64 %j0, %mask\n")
emith(" %ej = getelementptr inbounds [2 x i64], ptr %tab, i64 %j\n")
emith(" %kj = load i64, ptr %ej\n")
emith(" %endq = icmp eq i64 %kj, 0\n")
emith(" br i1 %endq, label %sh_end, label %sh_test\n")
emith("sh_test:\n")
emith(" %hj = call i64 @lp_fhash(i64 %kj)\n")
emith(" %home = and i64 %hj, %mask\n")
emith(" %jgt = icmp ugt i64 %j, %hole\n")
emith(" %a1 = icmp ugt i64 %home, %hole\n")
emith(" %a2 = icmp ule i64 %home, %j\n")
emith(" %in1 = and i1 %a1, %a2\n")
emith(" %in2 = or i1 %a1, %a2\n")
emith(" %in = select i1 %jgt, i1 %in1, i1 %in2\n")
emith(" br i1 %in, label %sh_skip, label %sh_move\n")
emith("sh_skip:\n")
emith(" br label %sh\n")
emith("sh_move:\n")
emith(" %eh = getelementptr inbounds [2 x i64], ptr %tab, i64 %hole\n")
emith(" store i64 %kj, ptr %eh\n")
emith(" %ejv = getelementptr inbounds i64, ptr %ej, i64 1\n")
emith(" %vj = load i64, ptr %ejv\n")
emith(" %ehv = getelementptr inbounds i64, ptr %eh, i64 1\n")
emith(" store i64 %vj, ptr %ehv\n")
emith(" br label %sh\n")
emith("sh_end:\n")
emith(" %ehe = getelementptr inbounds [2 x i64], ptr %tab, i64 %hole\n")
emith(" store i64 0, ptr %ehe\n")
emith(" br label %unlock\n")
emith("unlock:\n")
emith(" call void @lp_funlock()\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
}
function emit_fence_control() -> void {
emith("define internal i64 @lp_fenv(ptr %name, i64 %dflt) {\n")
emith("entry:\n")
emith(" %e = call ptr @getenv(ptr %name)\n")
emith(" %has = icmp ne ptr %e, null\n")
emith(" br i1 %has, label %read, label %none\n")
emith("read:\n")
emith(" %v = call i32 @atoi(ptr %e)\n")
emith(" %v64 = sext i32 %v to i64\n")
emith(" ret i64 %v64\n")
emith("none:\n")
emith(" ret i64 %dflt\n")
emith("}\n")
emith("define internal void @lp_finit() {\n")
emith("entry:\n")
emith(" %m0 = load i8, ptr @lp_fm\n")
emith(" %done = icmp ne i8 %m0, 0\n")
emith(" br i1 %done, label %out, label %go\n")
emith("go:\n")
emith(" %e = call ptr @getenv(ptr @.lpf_env)\n")
emith(" %has = icmp ne ptr %e, null\n")
emith(" br i1 %has, label %parse, label %dflt\n")
emith("parse:\n")
emith(" %c1 = call i32 @strcmp(ptr %e, ptr @.lpf_off)\n")
emith(" %is1 = icmp eq i32 %c1, 0\n")
emith(" %c2 = call i32 @strcmp(ptr %e, ptr @.lpf_count)\n")
emith(" %is2 = icmp eq i32 %c2, 0\n")
emith(" %c3 = call i32 @strcmp(ptr %e, ptr @.lpf_warn)\n")
emith(" %is3 = icmp eq i32 %c3, 0\n")
emith(" %ma = select i1 %is3, i8 3, i8 4\n")
emith(" %mb = select i1 %is2, i8 2, i8 %ma\n")
emith(" %mc = select i1 %is1, i8 1, i8 %mb\n")
emith(" br label %set\n")
emith("dflt:\n")
emith(" %d = load i8, ptr @lp_fdef\n")
emith(" %dz = icmp eq i8 %d, 0\n")
emith(" br i1 %dz, label %dev, label %set\n")
emith("dev:\n")
emith(" %dv = call ptr @getenv(ptr @.lpf_dev)\n")
emith(" %hd = icmp ne ptr %dv, null\n")
emith(" %md = select i1 %hd, i8 4, i8 1\n")
emith(" br label %set\n")
emith("set:\n")
emith(" %mode = phi i8 [ %mc, %parse ], [ %d, %dflt ], [ %md, %dev ]\n")
emith(" store i8 %mode, ptr @lp_fm\n")
emith(" %wd = load i64, ptr @lp_warm\n")
emith(" %w = call i64 @lp_fenv(ptr @.lpf_warm, i64 %wd)\n")
emith(" store i64 %w, ptr @lp_warm\n")
emith(" %wx5 = mul i64 %w, 5\n")
emith(" %wm = call i64 @lp_fenv(ptr @.lpf_warmmax, i64 %wx5)\n")
emith(" store i64 %wm, ptr @lp_warm_max\n")
emith(" %au = call i64 @lp_fenv(ptr @.lpf_auto, i64 1)\n")
emith(" %au8 = trunc i64 %au to i8\n")
emith(" store i8 %au8, ptr @lp_fauto\n")
emith(" %pl = call i64 @lp_fenv(ptr @.lpf_play, i64 -1)\n")
emith(" store i64 %pl, ptr @lp_autoplay\n")
emith(" %want = call i64 @lp_fenv(ptr @.lpf_tab, i64 4194304)\n")
emith(" br label %cap\n")
emith("cap:\n")
emith(" %c = phi i64 [ 1024, %set ], [ %c2x, %grow ]\n")
emith(" %big = icmp sge i64 %c, %want\n")
emith(" br i1 %big, label %capped, label %grow\n")
emith("grow:\n")
emith(" %c2x = shl i64 %c, 1\n")
emith(" br label %cap\n")
emith("capped:\n")
emith(" %mask = sub i64 %c, 1\n")
emith(" store i64 %mask, ptr @lp_tabmask\n")
emith(" %q = lshr i64 %c, 2\n")
emith(" %max = mul i64 %q, 3\n")
emith(" store i64 %max, ptr @lp_tabmax\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_fsnap() {\n")
emith("entry:\n")
emith(" %lv = load i64, ptr @lp_live\n")
emith(" store i64 %lv, ptr @lp_mlive\n")
emith(" %dlm = load i64, ptr @lp_dlive\n")
emith(" store i64 %dlm, ptr @lp_mdlive\n")
emith(" %pr = load i64, ptr @lp_pre\n")
emith(" store i64 %pr, ptr @lp_mpre\n")
emith(" %md = load i64, ptr @lp_made\n")
emith(" store i64 %md, ptr @lp_mmade\n")
emith(" %fr = load i64, ptr @lp_freed\n")
emith(" store i64 %fr, ptr @lp_mfreed\n")
emith(" store i32 0, ptr @lp_ntouch\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_fsnap_all() {\n")
emith("entry:\n")
emith(" %n = load i32, ptr @lp_site_n\n")
emith(" %n64 = zext i32 %n to i64\n")
emith(" %b = shl i64 %n64, 3\n")
emith(" call ptr @memcpy(ptr @lp_site_mark, ptr @lp_site_live, i64 %b)\n")
emith(" call void @lp_fsnap()\n")
emith(" ret void\n")
emith("}\n")
emith("define void @lp_mem_play() {\n")
emith("entry:\n")
emith(" call void @lp_finit()\n")
emith(" %m = load i8, ptr @lp_fm\n")
emith(" %off = icmp ule i8 %m, 1\n")
emith(" br i1 %off, label %out, label %chk\n")
emith("chk:\n")
emith(" %f = load i64, ptr @lp_frame\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %on = icmp ne i8 %t, 0\n")
emith(" br i1 %on, label %rewarm, label %start\n")
emith("rewarm:\n")
emith(" call void @lp_flock()\n")
emith(" store i8 0, ptr @lp_fj\n")
emith(" store i64 0, ptr @lp_flat\n")
emith(" store i64 %f, ptr @lp_playf\n")
emith(" call void @lp_funlock()\n")
emith(" br label %out\n")
emith("start:\n")
emith(" %tab = load ptr, ptr @lp_tab\n")
emith(" %none = icmp eq ptr %tab, null\n")
emith(" br i1 %none, label %make, label %arm\n")
emith("make:\n")
emith(" %mask = load i64, ptr @lp_tabmask\n")
emith(" %c = add i64 %mask, 1\n")
emith(" %p = call ptr @calloc(i64 %c, i64 16)\n")
emith(" store ptr %p, ptr @lp_tab\n")
emith(" br label %arm\n")
emith("arm:\n")
emith(" store i64 %f, ptr @lp_playf\n")
emith(" store i64 0, ptr @lp_flat\n")
emith(" %cp0 = call ptr @getenv(ptr @.lpf_census)\n")
emith(" %cpd = load ptr, ptr @lp_census_def\n")
emith(" %hasenv = icmp ne ptr %cp0, null\n")
emith(" %cp = select i1 %hasenv, ptr %cp0, ptr %cpd\n")
emith(" store ptr %cp, ptr @lp_census\n")
emith(" %hascp = icmp ne ptr %cp, null\n")
emith(" br i1 %hascp, label %reg, label %go\n")
emith("reg:\n")
emith(" call i32 @atexit(ptr @lp_fcensus)\n")
emith(" br label %go\n")
emith("go:\n")
emith(" %ex = call i64 @lp_fenv(ptr @.lpf_exitscan, i64 0)\n")
emith(" %exq = icmp ne i64 %ex, 0\n")
emith(" br i1 %exq, label %regx, label %go2\n")
emith("regx:\n")
emith(" call i32 @atexit(ptr @lp_fexitscan)\n")
emith(" br label %go2\n")
emith("go2:\n")
emith(" call void @lp_fsnap_all()\n")
emith(" store i8 1, ptr @lp_ft\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("define void @lp_mem_settled() {\n")
emith("entry:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %on = icmp ne i8 %t, 0\n")
emith(" br i1 %on, label %chk, label %out\n")
emith("chk:\n")
emith(" %j = load i8, ptr @lp_fj\n")
emith(" %already = icmp ne i8 %j, 0\n")
emith(" br i1 %already, label %out, label %go\n")
emith("go:\n")
emith(" call void @lp_flock()\n")
emith(" call void @lp_fsnap_all()\n")
emith(" call void @lp_fsettle_locked()\n")
emith(" call void @lp_funlock()\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("define i64 @lp_mem_kept() {\n")
emith("entry:\n")
emith(" %j = load i8, ptr @lp_fj\n")
emith(" %on = icmp ne i8 %j, 0\n")
emith(" br i1 %on, label %read, label %none\n")
emith("none:\n")
emith(" ret i64 0\n")
emith("read:\n")
emith(" call void @lp_flock()\n")
emith(" %lv = load i64, ptr @lp_live\n")
emith(" %sl = load i64, ptr @lp_slive\n")
emith(" %pr = load i64, ptr @lp_pre\n")
emith(" %sp = load i64, ptr @lp_spre\n")
emith(" %a = sub i64 %lv, %sl\n")
emith(" %b = sub i64 %pr, %sp\n")
emith(" %k = sub i64 %a, %b\n")
emith(" call void @lp_funlock()\n")
emith(" ret i64 %k\n")
emith("}\n")
emith("define i64 @lp_mem_bad_frames() {\n")
emith("entry:\n")
emith(" %b = load i64, ptr @lp_fbad\n")
emith(" ret i64 %b\n")
emith("}\n")
}
function emit_fence_report() -> void {
emith("define internal i64 @lp_fdelta(i32 %s, ptr %base) {\n")
emith("entry:\n")
emith(" %sp = getelementptr inbounds i64, ptr @lp_site_live, i32 %s\n")
emith(" %v = load i64, ptr %sp\n")
emith(" %mp = getelementptr inbounds i64, ptr %base, i32 %s\n")
emith(" %m = load i64, ptr %mp\n")
emith(" %d = sub i64 %v, %m\n")
emith(" ret i64 %d\n")
emith("}\n")
emith("define internal i32 @lp_fsite_at(i32 %i, i1 %all) {\n")
emith("entry:\n")
emith(" br i1 %all, label %every, label %touched\n")
emith("every:\n")
emith(" ret i32 %i\n")
emith("touched:\n")
emith(" %tp = getelementptr inbounds [512 x i32], ptr @lp_touch, i32 0, i32 %i\n")
emith(" %s = load i32, ptr %tp\n")
emith(" ret i32 %s\n")
emith("}\n")
emith("define internal { i64, i32 } @lp_fpick(ptr %base, i1 %all, i32 %cnt, i64 %pb, i32 %ps) {\n")
emith("entry:\n")
emith(" br label %loop\n")
emith("loop:\n")
emith(" %i = phi i32 [ 0, %entry ], [ %i1, %body ]\n")
emith(" %bb0 = phi i64 [ 0, %entry ], [ %bb1, %body ]\n")
emith(" %bs0 = phi i32 [ -1, %entry ], [ %bs1, %body ]\n")
emith(" %go = icmp ult i32 %i, %cnt\n")
emith(" br i1 %go, label %body, label %done\n")
emith("body:\n")
emith(" %s = call i32 @lp_fsite_at(i32 %i, i1 %all)\n")
emith(" %d = call i64 @lp_fdelta(i32 %s, ptr %base)\n")
emith(" %pos = icmp sgt i64 %d, 0\n")
emith(" %lt = icmp slt i64 %d, %pb\n")
emith(" %eqb = icmp eq i64 %d, %pb\n")
emith(" %gts = icmp sgt i32 %s, %ps\n")
emith(" %tie = and i1 %eqb, %gts\n")
emith(" %below = or i1 %lt, %tie\n")
emith(" %gtb = icmp sgt i64 %d, %bb0\n")
emith(" %eqbb = icmp eq i64 %d, %bb0\n")
emith(" %lts = icmp slt i32 %s, %bs0\n")
emith(" %tie2 = and i1 %eqbb, %lts\n")
emith(" %better = or i1 %gtb, %tie2\n")
emith(" %c1 = and i1 %pos, %below\n")
emith(" %take = and i1 %c1, %better\n")
emith(" %bb1 = select i1 %take, i64 %d, i64 %bb0\n")
emith(" %bs1 = select i1 %take, i32 %s, i32 %bs0\n")
emith(" %i1 = add i32 %i, 1\n")
emith(" br label %loop\n")
emith("done:\n")
emith(" %r0 = insertvalue { i64, i32 } undef, i64 %bb0, 0\n")
emith(" %r1 = insertvalue { i64, i32 } %r0, i32 %bs0, 1\n")
emith(" ret { i64, i32 } %r1\n")
emith("}\n")
emith("define internal void @lp_fsite_row(ptr %fp, i32 %fd, i64 %bytes, i32 %s) {\n")
emith("entry:\n")
emith(" %fnp = getelementptr inbounds ptr, ptr @lp_site_fn, i32 %s\n")
emith(" %fn = load ptr, ptr %fnp\n")
emith(" %flp = getelementptr inbounds ptr, ptr @lp_site_file, i32 %s\n")
emith(" %fl = load ptr, ptr %flp\n")
emith(" %lnp = getelementptr inbounds i32, ptr @lp_site_line, i32 %s\n")
emith(" %ln = load i32, ptr %lnp\n")
emith(" %kdp = getelementptr inbounds ptr, ptr @lp_site_kind, i32 %s\n")
emith(" %kd = load ptr, ptr %kdp\n")
emith(" %tofile = icmp ne ptr %fp, null\n")
emith(" br i1 %tofile, label %file, label %err\n")
emith("file:\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_crow, i64 %bytes, ptr %fn, ptr %fl, i32 %ln, ptr %kd)\n")
emith(" br label %from\n")
emith("err:\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 %fd, ptr @.lpf_row, i64 %bytes, ptr %fn, ptr %fl, i32 %ln, ptr %kd)\n")
emith(" br label %from\n")
emith("from:\n")
emith(" call void @lp_fsite_from(ptr %fp, i32 %s, ptr %fn)\n")
emith(" ret void\n")
emith("}\n")
emith("; the largest `rows` sites by what they hold over `base`, largest first\n")
emith("define internal void @lp_franked(ptr %fp, ptr %base, i1 %all, i32 %cnt, i32 %rows) {\n")
emith("entry:\n")
emith(" br label %pass\n")
emith("pass:\n")
emith(" %row = phi i32 [ 0, %entry ], [ %row1, %show ]\n")
emith(" %pb = phi i64 [ 9223372036854775807, %entry ], [ %bb, %show ]\n")
emith(" %ps = phi i32 [ -1, %entry ], [ %bs, %show ]\n")
emith(" %more = icmp ult i32 %row, %rows\n")
emith(" br i1 %more, label %scan, label %tail\n")
emith("scan:\n")
emith(" %r = call { i64, i32 } @lp_fpick(ptr %base, i1 %all, i32 %cnt, i64 %pb, i32 %ps)\n")
emith(" %bb = extractvalue { i64, i32 } %r, 0\n")
emith(" %bs = extractvalue { i64, i32 } %r, 1\n")
emith(" %found = icmp sge i32 %bs, 0\n")
emith(" br i1 %found, label %show, label %tail\n")
emith("show:\n")
emith(" call void @lp_fsite_row(ptr %fp, i32 2, i64 %bb, i32 %bs)\n")
emith(" %row1 = add i32 %row, 1\n")
emith(" br label %pass\n")
emith("tail:\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_freport(i64 %f, i64 %kept) {\n")
emith("entry:\n")
emith(" %md = load i64, ptr @lp_made\n")
emith(" %mm = load i64, ptr @lp_mmade\n")
emith(" %made = sub i64 %md, %mm\n")
emith(" %fr = load i64, ptr @lp_freed\n")
emith(" %mf = load i64, ptr @lp_mfreed\n")
emith(" %freed = sub i64 %fr, %mf\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_hdr, i64 %f, i64 %kept, i64 %made, i64 %freed)\n")
emith(" %nt = load i32, ptr @lp_ntouch\n")
emith(" %all = icmp ugt i32 %nt, 512\n")
emith(" %sn = load i32, ptr @lp_site_n\n")
emith(" %cnt = select i1 %all, i32 %sn, i32 %nt\n")
emith(" call void @lp_franked(ptr null, ptr @lp_site_mark, i1 %all, i32 %cnt, i32 12)\n")
emith(" ret void\n")
emith("}\n")
emith("; R3D_ALLOC_CENSUS=<file>, written at exit: the run's totals since play settled, and every site\n")
emith("; that holds more than it did then, largest first\n")
emith("define void @lp_fcensus() {\n")
emith("entry:\n")
emith(" %path = load ptr, ptr @lp_census\n")
emith(" %none = icmp eq ptr %path, null\n")
emith(" br i1 %none, label %out, label %open\n")
emith("open:\n")
emith(" %zn = call i64 @lp_fzone()\n")
emith(" %jn = call i64 @lp_fnat(ptr @.lpf_jb)\n")
emith(" %jpk = call i64 @lp_fnat(ptr @.lpf_jp)\n")
emith(" %vn = call i64 @lp_fnat(ptr @.lpf_vb)\n")
emith(" %vpk = call i64 @lp_fnat(ptr @.lpf_vp)\n")
emith(" %fp = call ptr @fopen(ptr %path, ptr @.lpf_w)\n")
emith(" %bad = icmp eq ptr %fp, null\n")
emith(" br i1 %bad, label %out, label %write\n")
emith("write:\n")
emith(" store i8 0, ptr @lp_ft\n")
emith(" %j = load i64, ptr @lp_fjudged\n")
emith(" %b = load i64, ptr @lp_fbad\n")
emith(" %k = call i64 @lp_mem_kept()\n")
emith(" %md = load i64, ptr @lp_made\n")
emith(" %fr = load i64, ptr @lp_freed\n")
emith(" %ov = load i64, ptr @lp_over\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_chdr, i64 %j, i64 %b, i64 %k, i64 %md, i64 %fr, i64 %ov)\n")
emith(" %jq = icmp ne i64 %j, 0\n")
emith(" %zs = load i64, ptr @lp_zset\n")
emith(" %zd = sub i64 %zn, %zs\n")
emith(" %js = load i64, ptr @lp_jset\n")
emith(" %jd = sub i64 %jn, %js\n")
emith(" %vs = load i64, ptr @lp_vset\n")
emith(" %vd = sub i64 %vn, %vs\n")
emith(" %dnw = load i64, ptr @lp_dlive\n")
emith(" %dst = load i64, ptr @lp_sdlive\n")
emith(" %dgr = sub i64 %dnw, %dst\n")
emith(" %nat0 = sub i64 %zd, %k\n")
emith(" %nat = sub i64 %nat0, %dgr\n")
emith(" %nat2 = sub i64 %nat, %jd\n")
emith(" %nat3 = sub i64 %nat2, %vd\n")
emith(" %nat1 = select i1 %jq, i64 %nat3, i64 0\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_cnat, i64 %nat1)\n")
emith(" %dnow = load i64, ptr @lp_dlive\n")
emith(" %dset = load i64, ptr @lp_sdlive\n")
emith(" %ddc = sub i64 %dnow, %dset\n")
emith(" %ddc1 = select i1 %jq, i64 %ddc, i64 0\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_cdecl, i64 %ddc1)\n")
emith(" %capn = load i64, ptr @lp_capn\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_ccap, i64 %capn)\n")
emith(" %ah0 = load i64, ptr @lp_ar_hw0\n")
emith(" %ah1 = load i64, ptr @lp_ar_hw1\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_car, i64 %ah0, i64 %ah1)\n")
emith(" %jd1 = select i1 %jq, i64 %jd, i64 0\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_cjolt, i64 %jd1, i64 %jpk)\n")
emith(" %vd1 = select i1 %jq, i64 %vd, i64 0\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_cvk, i64 %vd1, i64 %vpk)\n")
emith(" %sn = load i32, ptr @lp_site_n\n")
emith(" call void @lp_franked(ptr %fp, ptr @lp_site_base, i1 1, i32 %sn, i32 40)\n")
emith(" call void @lp_fowners(ptr %fp)\n")
emith(" call i32 @fclose(ptr %fp)\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
}
function emit_fence_frame() -> void {
emith("define internal void @lp_fmark_touched() {\n")
emith("entry:\n")
emith(" %nt = load i32, ptr @lp_ntouch\n")
emith(" %all = icmp ugt i32 %nt, 512\n")
emith(" br i1 %all, label %every, label %some\n")
emith("every:\n")
emith(" call void @lp_fsnap_all()\n")
emith(" ret void\n")
emith("some:\n")
emith(" br label %loop\n")
emith("loop:\n")
emith(" %i = phi i32 [ 0, %some ], [ %i1, %body ]\n")
emith(" %go = icmp ult i32 %i, %nt\n")
emith(" br i1 %go, label %body, label %done\n")
emith("body:\n")
emith(" %tp = getelementptr inbounds [512 x i32], ptr @lp_touch, i32 0, i32 %i\n")
emith(" %s = load i32, ptr %tp\n")
emith(" %sp = getelementptr inbounds i64, ptr @lp_site_live, i32 %s\n")
emith(" %v = load i64, ptr %sp\n")
emith(" %mp = getelementptr inbounds i64, ptr @lp_site_mark, i32 %s\n")
emith(" store i64 %v, ptr %mp\n")
emith(" %i1 = add i32 %i, 1\n")
emith(" br label %loop\n")
emith("done:\n")
emith(" call void @lp_fsnap()\n")
emith(" ret void\n")
emith("}\n")
emith("; malloc's live bytes over every zone (0 where there is no malloc_zone_statistics)\n")
emith("define internal i64 @lp_fzone() {\n")
emith("entry:\n")
emith(" %has = icmp ne ptr @malloc_zone_statistics, null\n")
emith(" br i1 %has, label %read, label %none\n")
emith("none:\n")
emith(" ret i64 0\n")
emith("read:\n")
emith(" %st = alloca [4 x i64], align 8\n")
emith(" call void @malloc_zone_statistics(ptr null, ptr %st)\n")
emith(" %p = getelementptr [4 x i64], ptr %st, i32 0, i32 1\n")
emith(" %n = load i64, ptr %p\n")
emith(" ret i64 %n\n")
emith("}\n")
emith("; a counted native library's number, found by name (ludic.physics' jph_heap_*, the Vulkan runtime's\n")
emith("; lvk_ac_*): 0 when the program does not carry it, and nothing is declared that the package declares\n")
emith("define internal i64 @lp_fnat(ptr %name) {\n")
emith("entry:\n")
emith(" %rtld_default = inttoptr i64 -2 to ptr\n")
emith(" %f = call ptr @dlsym(ptr %rtld_default, ptr %name)\n")
emith(" %none = icmp eq ptr %f, null\n")
emith(" br i1 %none, label %zero, label %call\n")
emith("zero:\n")
emith(" ret i64 0\n")
emith("call:\n")
emith(" %v = call i64 %f()\n")
emith(" ret i64 %v\n")
emith("}\n")
emith("; 25.5a: a list declared @max(n) grew past n, or a package's table filled (Mem.over): said under\n")
emith("; warn, and under fail the run ends with exit 87 - silent when the fence is off\n")
emith("define void @lp_cap_over(ptr %name, i32 %cap, i32 %len) {\n")
emith("entry:\n")
emith(" call void @lp_finit()\n")
emith(" %m = load i8, ptr @lp_fm\n")
emith(" %off = icmp ule i8 %m, 1\n")
emith(" br i1 %off, label %out, label %count\n")
emith("count:\n")
emith(" %c = load i64, ptr @lp_capn\n")
emith(" %c1 = add i64 %c, 1\n")
emith(" store i64 %c1, ptr @lp_capn\n")
emith(" %say = icmp uge i8 %m, 3\n")
emith(" br i1 %say, label %which, label %out\n")
emith("which:\n")
emith(" %isfull = icmp eq i32 %cap, 0\n")
emith(" br i1 %isfull, label %full, label %over\n")
emith("full:\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_full, ptr %name)\n")
emith(" br label %judge\n")
emith("over:\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_capover, ptr %name, i32 %cap, i32 %len)\n")
emith(" br label %judge\n")
emith("judge:\n")
emith(" %fail = icmp eq i8 %m, 4\n")
emith(" br i1 %fail, label %die, label %out\n")
emith("die:\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_capfail)\n")
emith(" call void @exit(i32 87)\n")
emith(" unreachable\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("; 25.5b: a leak by reachability. From every global (the states among them) each word that is the\n")
emith("; start of a heap block (malloc_size says so) is followed, conservatively, through every block; a\n")
emith("; tracked block nothing reaches is a leak whatever a frame's totals say. R3D_ALLOC_SCAN=<frame>\n")
emith("; runs it at that frame's mark (when no function is running), Mem.scan() whenever asked\n")
emith("define internal i1 @lp_vput(i64 %k) {\n")
emith("entry:\n")
emith(" %mask = load i64, ptr @lp_vmask\n")
emith(" %tab = load ptr, ptr @lp_visit_set\n")
emith(" %h = call i64 @lp_fhash(i64 %k)\n")
emith(" br label %probe\n")
emith("probe:\n")
emith(" %i = phi i64 [ %h, %entry ], [ %i1, %next ]\n")
emith(" %im = and i64 %i, %mask\n")
emith(" %e = getelementptr inbounds i64, ptr %tab, i64 %im\n")
emith(" %ek = load i64, ptr %e\n")
emith(" %empty = icmp eq i64 %ek, 0\n")
emith(" br i1 %empty, label %put, label %cmp\n")
emith("cmp:\n")
emith(" %same = icmp eq i64 %ek, %k\n")
emith(" br i1 %same, label %was, label %next\n")
emith("next:\n")
emith(" %i1 = add i64 %im, 1\n")
emith(" br label %probe\n")
emith("put:\n")
emith(" store i64 %k, ptr %e\n")
emith(" ret i1 1\n")
emith("was:\n")
emith(" ret i1 0\n")
emith("}\n")
emith("define internal i1 @lp_vhas(i64 %k) {\n")
emith("entry:\n")
emith(" %mask = load i64, ptr @lp_vmask\n")
emith(" %tab = load ptr, ptr @lp_visit_set\n")
emith(" %h = call i64 @lp_fhash(i64 %k)\n")
emith(" br label %probe\n")
emith("probe:\n")
emith(" %i = phi i64 [ %h, %entry ], [ %i1, %next ]\n")
emith(" %im = and i64 %i, %mask\n")
emith(" %e = getelementptr inbounds i64, ptr %tab, i64 %im\n")
emith(" %ek = load i64, ptr %e\n")
emith(" %empty = icmp eq i64 %ek, 0\n")
emith(" br i1 %empty, label %no, label %cmp\n")
emith("cmp:\n")
emith(" %same = icmp eq i64 %ek, %k\n")
emith(" br i1 %same, label %yes, label %next\n")
emith("next:\n")
emith(" %i1 = add i64 %im, 1\n")
emith(" br label %probe\n")
emith("yes:\n")
emith(" ret i1 1\n")
emith("no:\n")
emith(" ret i1 0\n")
emith("}\n")
emith("; a candidate is followed only if it could be a heap block's start: 16-aligned (malloc's), inside the\n")
emith("; user address space (above the first 4 GB, below 2^47 - a word with high bits is data, and some\n")
emith("; zones fault looking one up), and not in the frame arena; only then does malloc_size look at it\n")
emith("define internal void @lp_visit(i64 %w) {\n")
emith("entry:\n")
emith(" %al = and i64 %w, 15\n")
emith(" %mis = icmp ne i64 %al, 0\n")
emith(" %low = icmp ult i64 %w, 4294967296\n")
emith(" %high = icmp uge i64 %w, 140737488355328\n")
emith(" %s1 = or i1 %mis, %low\n")
emith(" %s2 = or i1 %s1, %high\n")
emith(" br i1 %s2, label %out, label %arena\n")
emith("arena:\n")
emith(" %wp = inttoptr i64 %w to ptr\n")
emith(" %inar = call i1 @lp_in_arena(ptr %wp)\n")
emith(" br i1 %inar, label %out, label %size\n")
emith("size:\n")
emith(" %p = inttoptr i64 %w to ptr\n")
emith(" %sz = call i64 @malloc_size(ptr %p)\n")
emith(" %nz = icmp eq i64 %sz, 0\n")
emith(" br i1 %nz, label %out, label %mark\n")
emith("mark:\n")
emith(" %new = call i1 @lp_vput(i64 %w)\n")
emith(" br i1 %new, label %queue, label %out\n")
emith("queue:\n")
emith(" %n = load i64, ptr @lp_wln\n")
emith(" %cap = load i64, ptr @lp_wlcap\n")
emith(" %full = icmp uge i64 %n, %cap\n")
emith(" br i1 %full, label %grow, label %push\n")
emith("grow:\n")
emith(" %nc0 = shl i64 %cap, 1\n")
emith(" %small = icmp ult i64 %nc0, 65536\n")
emith(" %nc = select i1 %small, i64 65536, i64 %nc0\n")
emith(" %old = load ptr, ptr @lp_wl\n")
emith(" %bytes = shl i64 %nc, 3\n")
emith(" %nw = call ptr @realloc(ptr %old, i64 %bytes)\n")
emith(" store ptr %nw, ptr @lp_wl\n")
emith(" store i64 %nc, ptr @lp_wlcap\n")
emith(" br label %push\n")
emith("push:\n")
emith(" %wl = load ptr, ptr @lp_wl\n")
emith(" %slot = getelementptr inbounds i64, ptr %wl, i64 %n\n")
emith(" store i64 %w, ptr %slot\n")
emith(" %n1 = add i64 %n, 1\n")
emith(" store i64 %n1, ptr @lp_wln\n")
emith(" br label %out\n")
emith("out:\n")
emith(" ret void\n")
emith("}\n")
emith("; R3D_ALLOC_EXIT=1: the same scan as the program quits - what nothing holds any more is what leaked\n")
emith("define internal void @lp_fexitscan() {\n")
emith("entry:\n")
emith(" call i64 @lp_mem_scan()\n")
emith(" ret void\n")
emith("}\n")
emith("define i64 @lp_mem_scan() {\n")
emith("entry:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %on = icmp ne i8 %t, 0\n")
emith(" %hasms = icmp ne ptr @malloc_size, null\n")
emith(" %go = and i1 %on, %hasms\n")
emith(" br i1 %go, label %prep, label %none\n")
emith("none:\n")
emith(" ret i64 0\n")
emith("prep:\n")
emith(" call void @lp_flock()\n")
emith(" %vs = load ptr, ptr @lp_visit_set\n")
emith(" %vnone = icmp eq ptr %vs, null\n")
emith(" br i1 %vnone, label %make, label %clear\n")
emith("make:\n")
emith(" %v = call ptr @calloc(i64 8388608, i64 8)\n")
emith(" store ptr %v, ptr @lp_visit_set\n")
emith(" store i64 8388607, ptr @lp_vmask\n")
emith(" br label %roots\n")
emith("clear:\n")
emith(" call ptr @memset(ptr %vs, i32 0, i64 67108864)\n")
emith(" br label %roots\n")
emith("roots:\n")
emith(" store i64 0, ptr @lp_wln\n")
emith(" %nr = load i32, ptr @lp_nroots\n")
emith(" br label %rl\n")
emith("rl:\n")
emith(" %ri = phi i32 [ 0, %roots ], [ %ri1, %rb ]\n")
emith(" %rgo = icmp ult i32 %ri, %nr\n")
emith(" br i1 %rgo, label %rb, label %walk\n")
emith("rb:\n")
emith(" %rp = getelementptr inbounds ptr, ptr @lp_roots, i32 %ri\n")
emith(" %g = load ptr, ptr %rp\n")
emith(" %gv = load i64, ptr %g\n")
emith(" call void @lp_visit(i64 %gv)\n")
emith(" %ri1 = add i32 %ri, 1\n")
emith(" br label %rl\n")
emith("walk:\n")
emith(" %n = load i64, ptr @lp_wln\n")
emith(" %done = icmp eq i64 %n, 0\n")
emith(" br i1 %done, label %sweep, label %pop\n")
emith("pop:\n")
emith(" %n1 = sub i64 %n, 1\n")
emith(" store i64 %n1, ptr @lp_wln\n")
emith(" %wl = load ptr, ptr @lp_wl\n")
emith(" %sp = getelementptr inbounds i64, ptr %wl, i64 %n1\n")
emith(" %b = load i64, ptr %sp\n")
emith(" %bp = inttoptr i64 %b to ptr\n")
emith(" %bsz = call i64 @malloc_size(ptr %bp)\n")
emith(" %words = lshr i64 %bsz, 3\n")
emith(" br label %wordl\n")
emith("wordl:\n")
emith(" %wi = phi i64 [ 0, %pop ], [ %wi1, %wordb ]\n")
emith(" %wgo = icmp ult i64 %wi, %words\n")
emith(" br i1 %wgo, label %wordb, label %walk\n")
emith("wordb:\n")
emith(" %wp = getelementptr inbounds i64, ptr %bp, i64 %wi\n")
emith(" %wv = load i64, ptr %wp\n")
emith(" call void @lp_visit(i64 %wv)\n")
emith(" %wi1 = add i64 %wi, 1\n")
emith(" br label %wordl\n")
emith("sweep:\n")
emith(" %sn = load i32, ptr @lp_site_n\n")
emith(" %sn64 = zext i32 %sn to i64\n")
emith(" %sb = shl i64 %sn64, 3\n")
emith(" call ptr @memset(ptr @lp_site_scan, i32 0, i64 %sb)\n")
emith(" %mask = load i64, ptr @lp_tabmask\n")
emith(" %cap = add i64 %mask, 1\n")
emith(" %tab = load ptr, ptr @lp_tab\n")
emith(" br label %tl\n")
emith("tl:\n")
emith(" %ti = phi i64 [ 0, %sweep ], [ %ti1, %tnext ]\n")
emith(" %lost = phi i64 [ 0, %sweep ], [ %lost2, %tnext ]\n")
emith(" %lostn = phi i64 [ 0, %sweep ], [ %lostn2, %tnext ]\n")
emith(" %tgo = icmp ult i64 %ti, %cap\n")
emith(" br i1 %tgo, label %tb, label %report\n")
emith("tb:\n")
emith(" %e = getelementptr inbounds [2 x i64], ptr %tab, i64 %ti\n")
emith(" %ek = load i64, ptr %e\n")
emith(" %empty = icmp eq i64 %ek, 0\n")
emith(" br i1 %empty, label %tnext, label %tchk\n")
emith("tchk:\n")
emith(" %seen = call i1 @lp_vhas(i64 %ek)\n")
emith(" br i1 %seen, label %tnext, label %tlost\n")
emith("tlost:\n")
emith(" %ev = getelementptr inbounds i64, ptr %e, i64 1\n")
emith(" %val = load i64, ptr %ev\n")
emith(" %sz = and i64 %val, 549755813887\n")
emith(" %site = lshr i64 %val, 40\n")
emith(" %ssp = getelementptr inbounds i64, ptr @lp_site_scan, i64 %site\n")
emith(" %sv = load i64, ptr %ssp\n")
emith(" %sv1 = add i64 %sv, %sz\n")
emith(" store i64 %sv1, ptr %ssp\n")
emith(" br label %tnext\n")
emith("tnext:\n")
emith(" %add = phi i64 [ 0, %tb ], [ 0, %tchk ], [ %sz, %tlost ]\n")
emith(" %addn = phi i64 [ 0, %tb ], [ 0, %tchk ], [ 1, %tlost ]\n")
emith(" %lost2 = add i64 %lost, %add\n")
emith(" %lostn2 = add i64 %lostn, %addn\n")
emith(" %ti1 = add i64 %ti, 1\n")
emith(" br label %tl\n")
emith("report:\n")
emith(" store i64 %lost, ptr @lp_scan_bytes\n")
emith(" %f = load i64, ptr @lp_frame\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_shdr, i64 %f, i64 %lost, i64 %lostn)\n")
emith(" %top = call i64 @lp_fenv(ptr @.lpf_scantop, i64 24)\n")
emith(" %top32 = trunc i64 %top to i32\n")
emith(" call void @lp_franked_vals(ptr @lp_site_scan, i32 %sn, i32 %top32)\n")
emith(" %sfp = call ptr @getenv(ptr @.lpf_scanfile)\n")
emith(" %hasf = icmp ne ptr %sfp, null\n")
emith(" br i1 %hasf, label %tofile, label %fin\n")
emith("tofile:\n")
emith(" %fh = call ptr @fopen(ptr %sfp, ptr @.lpf_a)\n")
emith(" %fok = icmp ne ptr %fh, null\n")
emith(" br i1 %fok, label %rows, label %fin\n")
emith("rows:\n")
emith(" %ri2 = phi i32 [ 0, %tofile ], [ %ri3, %rnext ]\n")
emith(" %more = icmp ult i32 %ri2, %sn\n")
emith(" br i1 %more, label %row, label %close\n")
emith("row:\n")
emith(" %rsp = getelementptr inbounds i64, ptr @lp_site_scan, i32 %ri2\n")
emith(" %rv = load i64, ptr %rsp\n")
emith(" %has = icmp sgt i64 %rv, 0\n")
emith(" br i1 %has, label %say, label %rnext\n")
emith("say:\n")
emith(" %fnp = getelementptr inbounds ptr, ptr @lp_site_fn, i32 %ri2\n")
emith(" %fn = load ptr, ptr %fnp\n")
emith(" %flp = getelementptr inbounds ptr, ptr @lp_site_file, i32 %ri2\n")
emith(" %fl = load ptr, ptr %flp\n")
emith(" %lnp = getelementptr inbounds i32, ptr @lp_site_line, i32 %ri2\n")
emith(" %ln = load i32, ptr %lnp\n")
emith(" %kdp = getelementptr inbounds ptr, ptr @lp_site_kind, i32 %ri2\n")
emith(" %kd = load ptr, ptr %kdp\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fh, ptr @.lpf_sfrow, i64 %rv, ptr %fn, ptr %fl, i32 %ln, ptr %kd)\n")
emith(" br label %rnext\n")
emith("rnext:\n")
emith(" %ri3 = add i32 %ri2, 1\n")
emith(" br label %rows\n")
emith("close:\n")
emith(" call i32 @fclose(ptr %fh)\n")
emith(" br label %fin\n")
emith("fin:\n")
emith(" call void @lp_funlock()\n")
emith(" ret i64 %lost\n")
emith("}\n")
emith("; 25.5c: the census by owner - what each state holds of what its sites made, and how much it grew\n")
emith("define internal void @lp_fowners(ptr %fp) {\n")
emith("entry:\n")
emith(" %no = load i32, ptr @lp_nowners\n")
emith(" %sn = load i32, ptr @lp_site_n\n")
emith(" br label %ol\n")
emith("ol:\n")
emith(" %o = phi i32 [ 1, %entry ], [ %o1, %onext ]\n")
emith(" %ogo = icmp ule i32 %o, %no\n")
emith(" br i1 %ogo, label %sl0, label %done\n")
emith("sl0:\n")
emith(" br label %sl\n")
emith("sl:\n")
emith(" %s = phi i32 [ 0, %sl0 ], [ %s1, %snext ]\n")
emith(" %live = phi i64 [ 0, %sl0 ], [ %live2, %snext ]\n")
emith(" %grew = phi i64 [ 0, %sl0 ], [ %grew2, %snext ]\n")
emith(" %sgo = icmp ult i32 %s, %sn\n")
emith(" br i1 %sgo, label %sb, label %say\n")
emith("sb:\n")
emith(" %op = getelementptr inbounds i32, ptr @lp_site_owner, i32 %s\n")
emith(" %ow = load i32, ptr %op\n")
emith(" %mine = icmp eq i32 %ow, %o\n")
emith(" %lp = getelementptr inbounds i64, ptr @lp_site_live, i32 %s\n")
emith(" %lv = load i64, ptr %lp\n")
emith(" %bp = getelementptr inbounds i64, ptr @lp_site_base, i32 %s\n")
emith(" %bv = load i64, ptr %bp\n")
emith(" %d = sub i64 %lv, %bv\n")
emith(" %la = select i1 %mine, i64 %lv, i64 0\n")
emith(" %da = select i1 %mine, i64 %d, i64 0\n")
emith(" %live2 = add i64 %live, %la\n")
emith(" %grew2 = add i64 %grew, %da\n")
emith(" br label %snext\n")
emith("snext:\n")
emith(" %s1 = add i32 %s, 1\n")
emith(" br label %sl\n")
emith("say:\n")
emith(" %any = icmp ne i64 %live, 0\n")
emith(" br i1 %any, label %print, label %onext\n")
emith("print:\n")
emith(" %oi = sub i32 %o, 1\n")
emith(" %np = getelementptr inbounds ptr, ptr @lp_owner_name, i32 %oi\n")
emith(" %nm = load ptr, ptr %np\n")
emith(" call i32 (ptr, ptr, ...) @fprintf(ptr %fp, ptr @.lpf_cown, ptr %nm, i64 %live, i64 %grew)\n")
emith(" br label %onext\n")
emith("onext:\n")
emith(" %o1 = add i32 %o, 1\n")
emith(" br label %ol\n")
emith("done:\n")
emith(" ret void\n")
emith("}\n")
emith("; the largest `rows` of a per-site array, largest first, to stderr (the scan's)\n")
emith("define internal void @lp_franked_vals(ptr %vals, i32 %cnt, i32 %rows) {\n")
emith("entry:\n")
emith(" br label %pass\n")
emith("pass:\n")
emith(" %row = phi i32 [ 0, %entry ], [ %row1, %show ]\n")
emith(" %pb = phi i64 [ 9223372036854775807, %entry ], [ %bb0, %show ]\n")
emith(" %ps = phi i32 [ -1, %entry ], [ %bs0, %show ]\n")
emith(" %more = icmp ult i32 %row, %rows\n")
emith(" br i1 %more, label %scan, label %tail\n")
emith("scan:\n")
emith(" br label %loop\n")
emith("loop:\n")
emith(" %i = phi i32 [ 0, %scan ], [ %i1, %body ]\n")
emith(" %bb0 = phi i64 [ 0, %scan ], [ %bb1, %body ]\n")
emith(" %bs0 = phi i32 [ -1, %scan ], [ %bs1, %body ]\n")
emith(" %go = icmp ult i32 %i, %cnt\n")
emith(" br i1 %go, label %body, label %done\n")
emith("body:\n")
emith(" %vp = getelementptr inbounds i64, ptr %vals, i32 %i\n")
emith(" %d = load i64, ptr %vp\n")
emith(" %pos = icmp sgt i64 %d, 0\n")
emith(" %lt = icmp slt i64 %d, %pb\n")
emith(" %eqb = icmp eq i64 %d, %pb\n")
emith(" %gts = icmp sgt i32 %i, %ps\n")
emith(" %tie = and i1 %eqb, %gts\n")
emith(" %below = or i1 %lt, %tie\n")
emith(" %gtb = icmp sgt i64 %d, %bb0\n")
emith(" %c1 = and i1 %pos, %below\n")
emith(" %take = and i1 %c1, %gtb\n")
emith(" %bb1 = select i1 %take, i64 %d, i64 %bb0\n")
emith(" %bs1 = select i1 %take, i32 %i, i32 %bs0\n")
emith(" %i1 = add i32 %i, 1\n")
emith(" br label %loop\n")
emith("done:\n")
emith(" %found = icmp sge i32 %bs0, 0\n")
emith(" br i1 %found, label %show, label %tail\n")
emith("show:\n")
emith(" call void @lp_fsite_row(ptr null, i32 2, i64 %bb0, i32 %bs0)\n")
emith(" %row1 = add i32 %row, 1\n")
emith(" br label %pass\n")
emith("tail:\n")
emith(" ret void\n")
emith("}\n")
emith("define internal void @lp_fsettle_locked() {\n")
emith("entry:\n")
emith(" %n = load i32, ptr @lp_site_n\n")
emith(" %n64 = zext i32 %n to i64\n")
emith(" %nb = shl i64 %n64, 3\n")
emith(" call ptr @memcpy(ptr @lp_site_base, ptr @lp_site_live, i64 %nb)\n")
emith(" %lv = load i64, ptr @lp_live\n")
emith(" store i64 %lv, ptr @lp_slive\n")
emith(" %dls = load i64, ptr @lp_dlive\n")
emith(" store i64 %dls, ptr @lp_sdlive\n")
emith(" %pr = load i64, ptr @lp_pre\n")
emith(" store i64 %pr, ptr @lp_spre\n")
emith(" %jb = call i64 @lp_fnat(ptr @.lpf_jb)\n")
emith(" store i64 %jb, ptr @lp_jset\n")
emith(" %vb = call i64 @lp_fnat(ptr @.lpf_vb)\n")
emith(" store i64 %vb, ptr @lp_vset\n")
emith(" %z = call i64 @lp_fzone()\n")
emith(" store i64 %z, ptr @lp_zset\n")
emith(" store i8 1, ptr @lp_fj\n")
emith(" ret void\n")
emith("}\n")
emith("; the frame's mark. Tracking starts at the first one (R3D_ALLOC_AUTO=0: at Mem.play() or\n")
emith("; R3D_ALLOC_PLAY=<frame>); judging starts once R3D_ALLOC_WARM frames in a row kept nothing, or\n")
emith("; R3D_ALLOC_WARM_MAX frames after tracking (re)started, whichever is first\n")
emith("define void @lp_mem_frame() {\n")
emith("entry:\n")
emith(" call void @lp_ar_frame()\n")
emith(" call void @lp_finit()\n")
emith(" %f = load i64, ptr @lp_frame\n")
emith(" %f1 = add i64 %f, 1\n")
emith(" %m = load i8, ptr @lp_fm\n")
emith(" %off = icmp ule i8 %m, 1\n")
emith(" br i1 %off, label %tick, label %live\n")
emith("live:\n")
emith(" %t = load i8, ptr @lp_ft\n")
emith(" %on = icmp ne i8 %t, 0\n")
emith(" br i1 %on, label %tracking, label %maybe_play\n")
emith("maybe_play:\n")
emith(" %au = load i8, ptr @lp_fauto\n")
emith(" %auq = icmp ne i8 %au, 0\n")
emith(" %ap = load i64, ptr @lp_autoplay\n")
emith(" %apset = icmp sge i64 %ap, 0\n")
emith(" %apdue = icmp sge i64 %f1, %ap\n")
emith(" %apgo = and i1 %apset, %apdue\n")
emith(" %go = or i1 %auq, %apgo\n")
emith(" br i1 %go, label %play, label %tick\n")
emith("play:\n")
emith(" call void @lp_mem_play()\n")
emith(" br label %tick\n")
emith("tracking:\n")
emith(" call void @lp_flock()\n")
emith(" %ov = load i64, ptr @lp_over\n")
emith(" %ovq = icmp sgt i64 %ov, 0\n")
emith(" %rep = load i8, ptr @lp_overrep\n")
emith(" %repq = icmp eq i8 %rep, 0\n")
emith(" %fullnew = and i1 %ovq, %repq\n")
emith(" br i1 %fullnew, label %full, label %weigh\n")
emith("full:\n")
emith(" %tn = load i64, ptr @lp_tabn\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_full, i64 %tn)\n")
emith(" store i8 1, ptr @lp_overrep\n")
emith(" store i8 0, ptr @lp_fj\n")
emith(" br label %unlock\n")
emith("weigh:\n")
emith(" %lv = load i64, ptr @lp_live\n")
emith(" %ml = load i64, ptr @lp_mlive\n")
emith(" %pr = load i64, ptr @lp_pre\n")
emith(" %mp = load i64, ptr @lp_mpre\n")
emith(" %a = sub i64 %lv, %ml\n")
emith(" %b = sub i64 %pr, %mp\n")
emith(" %kept = sub i64 %a, %b\n")
emith(" %bad = icmp sgt i64 %kept, 0\n")
emith(" %j = load i8, ptr @lp_fj\n")
emith(" %judging = icmp ne i8 %j, 0\n")
emith(" br i1 %judging, label %judge, label %warming\n")
emith("warming:\n")
emith(" %fl = load i64, ptr @lp_flat\n")
emith(" %fl1 = add i64 %fl, 1\n")
emith(" %fl2 = select i1 %bad, i64 0, i64 %fl1\n")
emith(" store i64 %fl2, ptr @lp_flat\n")
emith(" %w = load i64, ptr @lp_warm\n")
emith(" %wset = icmp sge i64 %w, 0\n")
emith(" %wdone = icmp sge i64 %fl2, %w\n")
emith(" %byflat = and i1 %wset, %wdone\n")
emith(" %pf = load i64, ptr @lp_playf\n")
emith(" %since = sub i64 %f1, %pf\n")
emith(" %wm = load i64, ptr @lp_warm_max\n")
emith(" %wmset = icmp sge i64 %wm, 0\n")
emith(" %wmdone = icmp sge i64 %since, %wm\n")
emith(" %bycap = and i1 %wmset, %wmdone\n")
emith(" %settle = or i1 %byflat, %bycap\n")
emith(" br i1 %settle, label %settle_now, label %mark\n")
emith("settle_now:\n")
emith(" call void @lp_fsettle_locked()\n")
emith(" br label %mark\n")
emith("judge:\n")
emith(" %jd = load i64, ptr @lp_fjudged\n")
emith(" %jd1 = add i64 %jd, 1\n")
emith(" store i64 %jd1, ptr @lp_fjudged\n")
emith(" br i1 %bad, label %kept_some, label %mark\n")
emith("kept_some:\n")
emith(" %fk = load i64, ptr @lp_fkept\n")
emith(" %fk1 = add i64 %fk, %kept\n")
emith(" store i64 %fk1, ptr @lp_fkept\n")
emith(" %fb = load i64, ptr @lp_fbad\n")
emith(" %fb1 = add i64 %fb, 1\n")
emith(" store i64 %fb1, ptr @lp_fbad\n")
emith(" %say = icmp uge i8 %m, 3\n")
emith(" br i1 %say, label %say_it, label %mark\n")
emith("say_it:\n")
emith(" call void @lp_freport(i64 %f, i64 %kept)\n")
emith(" %fail = icmp eq i8 %m, 4\n")
emith(" br i1 %fail, label %die, label %mark\n")
emith("die:\n")
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_failing)\n")
emith(" store i8 0, ptr @lp_ft\n")
emith(" call void @lp_funlock()\n")
emith(" call void @exit(i32 86)\n")
emith(" unreachable\n")
emith("mark:\n")
emith(" call void @lp_fmark_touched()\n")
emith(" br label %unlock\n")
emith("unlock:\n")
emith(" call void @lp_funlock()\n")
emith(" br label %tick\n")
emith("tick:\n")
emith(" store i64 %f1, ptr @lp_frame\n")
emith(" %sa = load i64, ptr @lp_scan_at\n")
emith(" %sunread = icmp eq i64 %sa, -2\n")
emith(" br i1 %sunread, label %sread, label %scheck\n")
emith("sread:\n")
emith(" %sv = call i64 @lp_fenv(ptr @.lpf_scan, i64 -1)\n")
emith(" store i64 %sv, ptr @lp_scan_at\n")
emith(" br label %scheck\n")
emith("scheck:\n")
emith(" %sat = load i64, ptr @lp_scan_at\n")
emith(" %sdue = icmp eq i64 %sat, %f1\n")
emith(" br i1 %sdue, label %sdo, label %sout\n")
emith("sdo:\n")
emith(" call i64 @lp_mem_scan()\n")
emith(" br label %sout\n")
emith("sout:\n")
emith(" ret void\n")
emith("}\n")
}
function emit_fence_win() -> void {
emith("@lp_site = global i32 0\n")
emith("@lp_want = global i8 0\n")
emith("@lp_fdecl = global i32 0\n")
emith("define ptr @lp_malloc(i64 %n) {\n")
emith("entry:\n")
emith(" %p = tail call ptr @malloc(i64 %n)\n")
emith(" ret ptr %p\n")
emith("}\n")
emith("define ptr @lp_calloc(i64 %n, i64 %s) {\n")
emith("entry:\n")
emith(" %p = tail call ptr @calloc(i64 %n, i64 %s)\n")
emith(" ret ptr %p\n")
emith("}\n")
emith("define ptr @lp_realloc(ptr %o, i64 %n) {\n")
emith("entry:\n")
emith(" %p = tail call ptr @realloc(ptr %o, i64 %n)\n")
emith(" ret ptr %p\n")
emith("}\n")
emith("define void @lp_free(ptr %o) {\n")
emith("entry:\n")
emith(" tail call void @free(ptr %o)\n")
emith(" ret void\n")
emith("}\n")
emith("define void @lp_mem_play() {\n")
emith("entry:\n")
emith(" ret void\n")
emith("}\n")
emith("define void @lp_mem_settled() {\n")
emith("entry:\n")
emith(" ret void\n")
emith("}\n")
emith("define void @lp_mem_frame() {\n")
emith("entry:\n")
emith(" ret void\n")
emith("}\n")
emith("define i64 @lp_mem_kept() {\n")
emith("entry:\n")
emith(" ret i64 0\n")
emith("}\n")
emith("define i64 @lp_mem_bad_frames() {\n")
emith("entry:\n")
emith(" ret i64 0\n")
emith("}\n")
emith("define void @lp_cap_over(ptr %name, i32 %cap, i32 %len) {\n")
emith("entry:\n")
emith(" ret void\n")
emith("}\n")
emith("define i64 @lp_mem_scan() {\n")
emith("entry:\n")
emith(" ret i64 0\n")
emith("}\n")
}
function emit_fence_intern() -> void {
emith("@lp_itab = global [65536 x ptr] zeroinitializer\n")
emith("@lp_icount = global i64 0\n")
emith("define internal ptr @lp_copystr(ptr %s, i64 %n) {\n")
emith("entry:\n")
emith(" %n1 = add i64 %n, 1\n")
emith(" %p = call ptr @lp_malloc(i64 %n1)\n")
emith(" call ptr @memcpy(ptr %p, ptr %s, i64 %n1)\n")
emith(" ret ptr %p\n")
emith("}\n")
emith("define ptr @lp_intern(ptr %s) {\n")
emith("entry:\n")
emith(" %null = icmp eq ptr %s, null\n")
emith(" br i1 %null, label %none, label %hl\n")
emith("none:\n")
emith(" ret ptr null\n")
emith("hl:\n")
emith(" %i = phi i64 [ 0, %entry ], [ %i1, %hb ]\n")
emith(" %h = phi i64 [ -3750763034362895579, %entry ], [ %h2, %hb ]\n")
emith(" %cp = getelementptr i8, ptr %s, i64 %i\n")
emith(" %c = load i8, ptr %cp\n")
emith(" %end = icmp eq i8 %c, 0\n")
emith(" br i1 %end, label %probe, label %hb\n")
emith("hb:\n")
emith(" %cz = zext i8 %c to i64\n")
emith(" %h1 = xor i64 %h, %cz\n")
emith(" %h2 = mul i64 %h1, 1099511628211\n")
emith(" %i1 = add i64 %i, 1\n")
emith(" br label %hl\n")
emith("probe:\n")
emith(" %k = phi i64 [ 0, %hl ], [ %k1, %next ]\n")
emith(" %far = icmp uge i64 %k, 64\n")
emith(" br i1 %far, label %copy_only, label %look\n")
emith("look:\n")
emith(" %slot0 = add i64 %h, %k\n")
emith(" %slot = and i64 %slot0, 65535\n")
emith(" %sp = getelementptr [65536 x ptr], ptr @lp_itab, i64 0, i64 %slot\n")
emith(" %v = load ptr, ptr %sp\n")
emith(" %empty = icmp eq ptr %v, null\n")
emith(" br i1 %empty, label %store, label %cmp\n")
emith("cmp:\n")
emith(" %r = call i32 @strcmp(ptr %v, ptr %s)\n")
emith(" %same = icmp eq i32 %r, 0\n")
emith(" br i1 %same, label %found, label %next\n")
emith("next:\n")
emith(" %k1 = add i64 %k, 1\n")
emith(" br label %probe\n")
emith("found:\n")
emith(" ret ptr %v\n")
emith("store:\n")
emith(" %cnt = load i64, ptr @lp_icount\n")
emith(" %full = icmp uge i64 %cnt, 49152\n")
emith(" br i1 %full, label %copy_only, label %keep\n")
emith("keep:\n")
emith(" %c2 = call ptr @lp_copystr(ptr %s, i64 %i)\n")
emith(" store ptr %c2, ptr %sp\n")
emith(" %cnt1 = add i64 %cnt, 1\n")
emith(" store i64 %cnt1, ptr @lp_icount\n")
emith(" ret ptr %c2\n")
emith("copy_only:\n")
emith(" %c3 = call ptr @lp_copystr(ptr %s, i64 %i)\n")
emith(" ret ptr %c3\n")
emith("}\n")
}