fence (25.1): every allocation goes through the fence - sites, frame judging, census, callers
Every allocation the compiler emits goes through @lp_malloc/@lp_calloc/@lp_realloc/@lp_free, and a Ludic-level one first stores its site (function, file, line, kind) in @lp_site. Off, that is one load and a predictable branch (30 M allocations: 0.87-0.91 s against 0.87-0.90 s on leaks2). On (the default in a headless build, and windowed under R3D_DEV), tracking starts at the first frame on its own and judging once R3D_ALLOC_WARM frames in a row kept nothing (600) or R3D_ALLOC_WARM_MAX after (re)start; Mem.play()/Mem.rewarm() sends a load back to its warm-up. A judged frame that ends holding more than it began with is reported by site with its callers (the unwinder, taken only once judging) and fails the run with exit 86 (R3D_ALLOC_FENCE=off|count|warn|fail). R3D_ALLOC_CENSUS writes the totals and top sites at exit. The build's defaults are --fence=, --fence-warm=, --fence-census= or a fence line in the program's package.ludic; the environment overrides them. The runtime is IR (emit_fence_ir.ludic, generated from a template); tracking is a side table in one calloc'd region, so no block carries a header and pointers crossing to natives stay safe. Examples alloc_fence, alloc_fence_leak and alloc_fence_auto with cases in ludic-dev test; reseeded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fc0f3d3790
commit
a8d54e9878
34 changed files with 106868 additions and 82677 deletions
963
selfhost/backend/emit_fence_ir.ludic
Normal file
963
selfhost/backend/emit_fence_ir.ludic
Normal file
|
|
@ -0,0 +1,963 @@
|
|||
# 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_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_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("@.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_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_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("define ptr @lp_malloc(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_calloc(i64 %n, i64 %s) {\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 @calloc(i64 %n, i64 %s)\n")
|
||||
emith(" ret ptr %p\n")
|
||||
emith("slow:\n")
|
||||
emith(" %q = call ptr @calloc(i64 %n, i64 %s)\n")
|
||||
emith(" %b = mul i64 %n, %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(" %on = icmp ne i8 %t, 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(" call void @lp_fdel(ptr %o)\n")
|
||||
emith(" %q = call ptr @realloc(ptr %o, i64 %n)\n")
|
||||
emith(" call void @lp_fadd(ptr %q, i64 %n)\n")
|
||||
emith(" ret ptr %q\n")
|
||||
emith("}\n")
|
||||
emith("define void @lp_free(ptr %o) {\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(" tail call void @free(ptr %o)\n")
|
||||
emith(" ret void\n")
|
||||
emith("slow:\n")
|
||||
emith(" call void @lp_fdel(ptr %o)\n")
|
||||
emith(" call void @free(ptr %o)\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 %n) {\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(" %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, 1099511627775\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(" %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(" %v = or i64 %sh, %n\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(" 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, 1099511627775\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(" %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(" %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(" %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(" %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(" %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("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(" %pr = load i64, ptr @lp_pre\n")
|
||||
emith(" store i64 %pr, ptr @lp_spre\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_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(" ret void\n")
|
||||
emith("}\n")
|
||||
}
|
||||
function emit_fence_win() -> void {
|
||||
emith("@lp_site = 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")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue