keep(x) copies a string, a slice (header and elements) or a record (shallow) onto the heap; intern(s) hands back one heap string per distinct text from a fixed table in the runtime (FNV-1a, 65536 slots, copied the first time; past 49152 only copied). Both are how frame code keeps what it made on purpose: the escape analysis takes the copy as the heap's and leaves the argument LOCAL. The analysis now records why a class escapes (the store, the event, the global it reached) and ludic deps lists every allocation frame code makes and keeps - fkeep lines, 'ludic deps --keeps', the frame_keeps number --check ratchets - leaving out what is under @alloc_ok and a push's growth (25.5's capacities). --arena-strict (or 'arena strict') makes each an error naming the store, before anything is emitted. A test: a template stored into a state is the one error; keep and intern of the next two, an @alloc_ok push and a scratch temporary are not; 195 frames of arena resets under R3D_ARENA_CHECK=1 later the kept and interned texts read as made, and intern gives the same string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1380 lines
57 KiB
Text
1380 lines
57 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_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 [99 x i8] c\"alloc-fence: the table is full (%lld blocks) - raise R3D_ALLOC_TABLE; from here it judges nothing\\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_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(" %a = load i8, ptr @lp_ar_on\n")
|
|
emith(" %o1 = or i8 %t, %w\n")
|
|
emith(" %o2 = or i8 %o1, %a\n")
|
|
emith(" %on = icmp ne i8 %o2, 0\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(" %t = load i8, ptr @lp_ft\n")
|
|
emith(" %a = load i8, ptr @lp_ar_on\n")
|
|
emith(" %o1 = or i8 %t, %a\n")
|
|
emith(" %on = icmp ne i8 %o1, 0\n")
|
|
emith(" br i1 %on, label %slow, label %fast\n")
|
|
emith("fast:\n")
|
|
emith(" tail call void @free(ptr %o)\n")
|
|
emith(" ret void\n")
|
|
emith("slow:\n")
|
|
emith(" %in = call i1 @lp_in_arena(ptr %o)\n")
|
|
emith(" br i1 %in, label %keep, label %give\n")
|
|
emith("keep:\n")
|
|
emith(" ret void\n")
|
|
emith("give:\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_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(" call void @lp_fsite_add(i64 %ds, i64 %dneg)\n")
|
|
emith(" %dwd = and i64 %dold, 549755813888\n")
|
|
emith(" %dwas = icmp ne i64 %dwd, 0\n")
|
|
emith(" %ddl = load i64, ptr @lp_dlive\n")
|
|
emith(" %ddsub = select i1 %dwas, i64 %dn, i64 0\n")
|
|
emith(" %ddl1 = sub i64 %ddl, %ddsub\n")
|
|
emith(" store i64 %ddl1, ptr @lp_dlive\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(" %dl = load i64, ptr @lp_dlive\n")
|
|
emith(" %dadd = select i1 %isdecl, i64 %n, i64 0\n")
|
|
emith(" %dl1 = add i64 %dl, %dadd\n")
|
|
emith(" store i64 %dl1, ptr @lp_dlive\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(" 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(" call void @lp_fsite_add(i64 %s, i64 %neg)\n")
|
|
emith(" %wd = and i64 %v, 549755813888\n")
|
|
emith(" %wasdecl = icmp ne i64 %wd, 0\n")
|
|
emith(" %dl = load i64, ptr @lp_dlive\n")
|
|
emith(" %dsub = select i1 %wasdecl, i64 %n, i64 0\n")
|
|
emith(" %dl1 = sub i64 %dl, %dsub\n")
|
|
emith(" store i64 %dl1, ptr @lp_dlive\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, %found ], [ %hole, %sh_skip ], [ %j, %sh_move ]\n")
|
|
emith(" %jp = phi i64 [ %im, %found ], [ %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(" 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(" %a0 = sub i64 %lv, %sl\n")
|
|
emith(" %dlk = load i64, ptr @lp_dlive\n")
|
|
emith(" %sdl = load i64, ptr @lp_sdlive\n")
|
|
emith(" %ddk = sub i64 %dlk, %sdl\n")
|
|
emith(" %a = sub i64 %a0, %ddk\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(" %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 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("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(" %a0 = sub i64 %lv, %ml\n")
|
|
emith(" %dln = load i64, ptr @lp_dlive\n")
|
|
emith(" %dlmk = load i64, ptr @lp_mdlive\n")
|
|
emith(" %dd = sub i64 %dln, %dlmk\n")
|
|
emith(" %a = sub i64 %a0, %dd\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(" 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")
|
|
}
|
|
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")
|
|
}
|