reachability scan (25.5b) and exit accounting; free() and print release what they are handed
Mem.scan() and R3D_ALLOC_SCAN=<frame> (at that frame's mark, when no function is running) walk
every heap block reachable from the program's globals - the states among them - conservatively: each
word that is a heap block's start (malloc_size says so) is followed, blocks made before tracking too.
A tracked block nothing reaches is a leak whatever a frame's totals say; they are summed by site and
printed ('alloc-scan: frame 39 - 32 bytes in 2 blocks ... reachable from no global or state', then
the sites). R3D_ALLOC_EXIT=1 runs the same scan as the program quits. A test: two records dropped in
frame 20 are the two found, the one pushed into a state is not.
The escape analysis now takes free(x) as giving x back (ES_FREED, flowing to what reached x) and a
print's argument as used up, so ludic deps --births lists only what is never given back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3205408290
commit
39af9cabc0
7 changed files with 74517 additions and 71904 deletions
|
|
@ -16,6 +16,7 @@
|
|||
const ES_SCRATCH: int = 77 # Node.uns on an allocating expression: scratch
|
||||
const ES_ESC: int = 1
|
||||
const ES_HEAP: int = 2
|
||||
const ES_FREED: int = 4 # given back with free(): not a leak at birth
|
||||
|
||||
var g_es_flag: []int = new []int
|
||||
var g_es_why: []Node = new []Node # per class: the statement that made it escape
|
||||
|
|
@ -190,7 +191,18 @@ function es_call(e: Node) -> int {
|
|||
es_args_walk(e)
|
||||
return es_site(e)
|
||||
}
|
||||
if (nm == "print") or (nm == "len") or (nm == "free") { es_args_walk(e); return -1 }
|
||||
if (nm == "free") and len(e.kids) == 1 { # given back: what flows into it is not kept by nothing
|
||||
let v = es_val(e.kids[0])
|
||||
if v >= 0 { g_es_flag[v] = g_es_flag[v] | ES_FREED }
|
||||
return -1
|
||||
}
|
||||
if (nm == "print") { # print frees a fresh text it is handed
|
||||
es_args_walk(e)
|
||||
var i = 0
|
||||
while i < len(e.kids) { push(g_es_consumed, e.kids[i]); i += 1 }
|
||||
return -1
|
||||
}
|
||||
if (nm == "len") { es_args_walk(e); return -1 }
|
||||
let f = es_fn(nm)
|
||||
if f >= 0 {
|
||||
push(g_es_calls_f, g_es_cur)
|
||||
|
|
@ -327,6 +339,7 @@ function es_solve() -> void {
|
|||
let a = g_es_ff[i]
|
||||
let b = g_es_ft[i]
|
||||
if (g_es_flag[a] & ES_HEAP) != 0 and (g_es_flag[b] & ES_HEAP) == 0 { g_es_flag[b] = g_es_flag[b] | ES_HEAP; changed = true }
|
||||
if (g_es_flag[b] & ES_FREED) != 0 and (g_es_flag[a] & ES_FREED) == 0 { g_es_flag[a] = g_es_flag[a] | ES_FREED; changed = true }
|
||||
if (g_es_flag[b] & ES_ESC) != 0 and (g_es_flag[a] & ES_ESC) == 0 {
|
||||
g_es_flag[a] = g_es_flag[a] | ES_ESC
|
||||
g_es_why[a] = g_es_why[b]
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ var g_fence_mode: int = 0 # 0: headless fails, windowed fai
|
|||
var g_fence_warm: int = 600
|
||||
var g_fence_census: pointer = null
|
||||
var g_fence_flagged: bool = false # a flag said so: the manifest does not override it
|
||||
var g_scan_roots: []pointer = new []pointer # 25.5b: the program's pointer globals, the states among them
|
||||
var g_cap_keys: []pointer = new []pointer # 25.5a: `Type.field` declared @max(n) ...
|
||||
var g_cap_vals: []int = new []int # ... and its n
|
||||
var g_push_cap: int = 0 # the list being pushed to is capped (emit_push -> emit_push_into)
|
||||
|
|
@ -41,6 +42,7 @@ function fence_reset() -> void {
|
|||
g_mzs_declared = false
|
||||
g_mmap_declared = false
|
||||
g_es_node = null
|
||||
g_scan_roots = new []pointer
|
||||
g_cur_fn_name = "?"; g_site_fnc = null; g_site_filen = null; g_site_filec = null; g_site_next = null
|
||||
push(g_site_fn, null); push(g_site_file, null); push(g_site_line, 0); push(g_site_kind, null) # site 0, named at the end
|
||||
}
|
||||
|
|
@ -164,12 +166,13 @@ function fence_manifest_read(txt: pointer) -> void {
|
|||
|
||||
# Mem.play() / Mem.rewarm() / Mem.settled() / Mem.frame() / Mem.kept() / Mem.bad_frames()
|
||||
function is_mem_fence_ns(meth: pointer) -> bool {
|
||||
return (meth == "play") or (meth == "rewarm") or (meth == "settled") or (meth == "over") or (meth == "frame") or (meth == "kept") or (meth == "bad_frames")
|
||||
return (meth == "play") or (meth == "rewarm") or (meth == "settled") or (meth == "over") or (meth == "scan") or (meth == "frame") or (meth == "kept") or (meth == "bad_frames")
|
||||
}
|
||||
|
||||
function emit_mem_fence_ns(meth: pointer, e: Node) -> Val {
|
||||
if (meth == "kept") { return val(emit_bind("call i64 @lp_mem_kept()"), "long") }
|
||||
if (meth == "bad_frames") { return val(emit_bind("call i64 @lp_mem_bad_frames()"), "long") }
|
||||
if (meth == "scan") { return val(emit_bind("call i64 @lp_mem_scan()"), "long") }
|
||||
if (meth == "rewarm") { emit(" call void @lp_mem_play()\n"); return val("0", "void") }
|
||||
if (meth == "over") { # 25.5a: Mem.over("what") - a package's table is full
|
||||
let nm = emit_expr(e.kids[0])
|
||||
|
|
@ -230,6 +233,13 @@ function emit_fence_runtime() -> void {
|
|||
emith(`@lp_site_mark = global [{sn} x i64] zeroinitializer\n`)
|
||||
emith(`@lp_site_stamp = global [{sn} x i64] zeroinitializer\n`)
|
||||
emith(`@lp_site_base = global [{sn} x i64] zeroinitializer\n`)
|
||||
emith(`@lp_site_scan = global [{sn} x i64] zeroinitializer\n`)
|
||||
let roots = new []pointer
|
||||
var r = 0
|
||||
while r < len(g_scan_roots) { push(roots, `@g_{g_scan_roots[r]}`); r += 1 }
|
||||
if len(roots) == 0 { push(roots, "null") }
|
||||
fence_table("@lp_roots", "ptr", roots)
|
||||
emith(`@lp_nroots = global i32 {itoa(len(g_scan_roots))}\n`)
|
||||
emith(`@lp_site_ra = global [{itoa(n * 6)} x ptr] zeroinitializer\n`)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,13 @@ function emit_fence_globals() -> void {
|
|||
emith("@lp_fkept = global i64 0\n")
|
||||
emith("@lp_fbad = global i64 0\n")
|
||||
emith("@lp_fjudged = global i64 0\n")
|
||||
emith("@lp_scan_at = global i64 -2\n")
|
||||
emith("@lp_visit_set = global ptr null\n")
|
||||
emith("@lp_vmask = global i64 0\n")
|
||||
emith("@lp_wl = global ptr null\n")
|
||||
emith("@lp_wln = global i64 0\n")
|
||||
emith("@lp_wlcap = global i64 0\n")
|
||||
emith("@lp_scan_bytes = global i64 0\n")
|
||||
emith("@lp_capn = global i64 0\n")
|
||||
emith("@lp_zset = global i64 0\n")
|
||||
emith("@lp_jset = global i64 0\n")
|
||||
|
|
@ -82,6 +89,10 @@ function emit_fence_globals() -> void {
|
|||
emith("@.lpf_capover = private unnamed_addr constant [54 x i8] c\"alloc-fence: %s grew past its @max(%d) (it holds %d)\\0A\\00\"\n")
|
||||
emith("@.lpf_capfail = private unnamed_addr constant [78 x i8] c\"alloc-fence: failing the run (R3D_ALLOC_FENCE=fail): a capacity is a promise\\0A\\00\"\n")
|
||||
emith("@.lpf_ccap = private unnamed_addr constant [56 x i8] c\"overflows %lld (a list past its @max, or a table full)\\0A\\00\"\n")
|
||||
emith("@.lpf_scan = private unnamed_addr constant [15 x i8] c\"R3D_ALLOC_SCAN\\00\"\n")
|
||||
emith("@.lpf_exitscan = private unnamed_addr constant [15 x i8] c\"R3D_ALLOC_EXIT\\00\"\n")
|
||||
emith("@.lpf_shdr = private unnamed_addr constant [116 x i8] c\"alloc-scan: frame %lld - %lld bytes in %lld blocks made since tracking began are reachable from no global or state\\0A\\00\"\n")
|
||||
emith("@.lpf_srow = private unnamed_addr constant [25 x i8] c\" %lld B %s %s:%d %s\\0A\\00\"\n")
|
||||
emith("@.lpf_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")
|
||||
|
|
@ -854,6 +865,13 @@ function emit_fence_control() -> void {
|
|||
emith(" call i32 @atexit(ptr @lp_fcensus)\n")
|
||||
emith(" br label %go\n")
|
||||
emith("go:\n")
|
||||
emith(" %ex = call i64 @lp_fenv(ptr @.lpf_exitscan, i64 0)\n")
|
||||
emith(" %exq = icmp ne i64 %ex, 0\n")
|
||||
emith(" br i1 %exq, label %regx, label %go2\n")
|
||||
emith("regx:\n")
|
||||
emith(" call i32 @atexit(ptr @lp_fexitscan)\n")
|
||||
emith(" br label %go2\n")
|
||||
emith("go2:\n")
|
||||
emith(" call void @lp_fsnap_all()\n")
|
||||
emith(" store i8 1, ptr @lp_ft\n")
|
||||
emith(" br label %out\n")
|
||||
|
|
@ -1174,6 +1192,243 @@ function emit_fence_frame() -> void {
|
|||
emith("out:\n")
|
||||
emith(" ret void\n")
|
||||
emith("}\n")
|
||||
emith("; 25.5b: a leak by reachability. From every global (the states among them) each word that is the\n")
|
||||
emith("; start of a heap block (malloc_size says so) is followed, conservatively, through every block; a\n")
|
||||
emith("; tracked block nothing reaches is a leak whatever a frame's totals say. R3D_ALLOC_SCAN=<frame>\n")
|
||||
emith("; runs it at that frame's mark (when no function is running), Mem.scan() whenever asked\n")
|
||||
emith("define internal i1 @lp_vput(i64 %k) {\n")
|
||||
emith("entry:\n")
|
||||
emith(" %mask = load i64, ptr @lp_vmask\n")
|
||||
emith(" %tab = load ptr, ptr @lp_visit_set\n")
|
||||
emith(" %h = call i64 @lp_fhash(i64 %k)\n")
|
||||
emith(" br label %probe\n")
|
||||
emith("probe:\n")
|
||||
emith(" %i = phi i64 [ %h, %entry ], [ %i1, %next ]\n")
|
||||
emith(" %im = and i64 %i, %mask\n")
|
||||
emith(" %e = getelementptr inbounds i64, ptr %tab, i64 %im\n")
|
||||
emith(" %ek = load i64, ptr %e\n")
|
||||
emith(" %empty = icmp eq i64 %ek, 0\n")
|
||||
emith(" br i1 %empty, label %put, label %cmp\n")
|
||||
emith("cmp:\n")
|
||||
emith(" %same = icmp eq i64 %ek, %k\n")
|
||||
emith(" br i1 %same, label %was, label %next\n")
|
||||
emith("next:\n")
|
||||
emith(" %i1 = add i64 %im, 1\n")
|
||||
emith(" br label %probe\n")
|
||||
emith("put:\n")
|
||||
emith(" store i64 %k, ptr %e\n")
|
||||
emith(" ret i1 1\n")
|
||||
emith("was:\n")
|
||||
emith(" ret i1 0\n")
|
||||
emith("}\n")
|
||||
emith("define internal i1 @lp_vhas(i64 %k) {\n")
|
||||
emith("entry:\n")
|
||||
emith(" %mask = load i64, ptr @lp_vmask\n")
|
||||
emith(" %tab = load ptr, ptr @lp_visit_set\n")
|
||||
emith(" %h = call i64 @lp_fhash(i64 %k)\n")
|
||||
emith(" br label %probe\n")
|
||||
emith("probe:\n")
|
||||
emith(" %i = phi i64 [ %h, %entry ], [ %i1, %next ]\n")
|
||||
emith(" %im = and i64 %i, %mask\n")
|
||||
emith(" %e = getelementptr inbounds i64, ptr %tab, i64 %im\n")
|
||||
emith(" %ek = load i64, ptr %e\n")
|
||||
emith(" %empty = icmp eq i64 %ek, 0\n")
|
||||
emith(" br i1 %empty, label %no, label %cmp\n")
|
||||
emith("cmp:\n")
|
||||
emith(" %same = icmp eq i64 %ek, %k\n")
|
||||
emith(" br i1 %same, label %yes, label %next\n")
|
||||
emith("next:\n")
|
||||
emith(" %i1 = add i64 %im, 1\n")
|
||||
emith(" br label %probe\n")
|
||||
emith("yes:\n")
|
||||
emith(" ret i1 1\n")
|
||||
emith("no:\n")
|
||||
emith(" ret i1 0\n")
|
||||
emith("}\n")
|
||||
emith("define internal void @lp_visit(i64 %w) {\n")
|
||||
emith("entry:\n")
|
||||
emith(" %z = icmp eq i64 %w, 0\n")
|
||||
emith(" %al = and i64 %w, 7\n")
|
||||
emith(" %mis = icmp ne i64 %al, 0\n")
|
||||
emith(" %skip = or i1 %z, %mis\n")
|
||||
emith(" br i1 %skip, label %out, label %size\n")
|
||||
emith("size:\n")
|
||||
emith(" %p = inttoptr i64 %w to ptr\n")
|
||||
emith(" %sz = call i64 @malloc_size(ptr %p)\n")
|
||||
emith(" %nz = icmp eq i64 %sz, 0\n")
|
||||
emith(" br i1 %nz, label %out, label %mark\n")
|
||||
emith("mark:\n")
|
||||
emith(" %new = call i1 @lp_vput(i64 %w)\n")
|
||||
emith(" br i1 %new, label %queue, label %out\n")
|
||||
emith("queue:\n")
|
||||
emith(" %n = load i64, ptr @lp_wln\n")
|
||||
emith(" %cap = load i64, ptr @lp_wlcap\n")
|
||||
emith(" %full = icmp uge i64 %n, %cap\n")
|
||||
emith(" br i1 %full, label %grow, label %push\n")
|
||||
emith("grow:\n")
|
||||
emith(" %nc0 = shl i64 %cap, 1\n")
|
||||
emith(" %small = icmp ult i64 %nc0, 65536\n")
|
||||
emith(" %nc = select i1 %small, i64 65536, i64 %nc0\n")
|
||||
emith(" %old = load ptr, ptr @lp_wl\n")
|
||||
emith(" %bytes = shl i64 %nc, 3\n")
|
||||
emith(" %nw = call ptr @realloc(ptr %old, i64 %bytes)\n")
|
||||
emith(" store ptr %nw, ptr @lp_wl\n")
|
||||
emith(" store i64 %nc, ptr @lp_wlcap\n")
|
||||
emith(" br label %push\n")
|
||||
emith("push:\n")
|
||||
emith(" %wl = load ptr, ptr @lp_wl\n")
|
||||
emith(" %slot = getelementptr inbounds i64, ptr %wl, i64 %n\n")
|
||||
emith(" store i64 %w, ptr %slot\n")
|
||||
emith(" %n1 = add i64 %n, 1\n")
|
||||
emith(" store i64 %n1, ptr @lp_wln\n")
|
||||
emith(" br label %out\n")
|
||||
emith("out:\n")
|
||||
emith(" ret void\n")
|
||||
emith("}\n")
|
||||
emith("; R3D_ALLOC_EXIT=1: the same scan as the program quits - what nothing holds any more is what leaked\n")
|
||||
emith("define internal void @lp_fexitscan() {\n")
|
||||
emith("entry:\n")
|
||||
emith(" call i64 @lp_mem_scan()\n")
|
||||
emith(" ret void\n")
|
||||
emith("}\n")
|
||||
emith("define i64 @lp_mem_scan() {\n")
|
||||
emith("entry:\n")
|
||||
emith(" %t = load i8, ptr @lp_ft\n")
|
||||
emith(" %on = icmp ne i8 %t, 0\n")
|
||||
emith(" %hasms = icmp ne ptr @malloc_size, null\n")
|
||||
emith(" %go = and i1 %on, %hasms\n")
|
||||
emith(" br i1 %go, label %prep, label %none\n")
|
||||
emith("none:\n")
|
||||
emith(" ret i64 0\n")
|
||||
emith("prep:\n")
|
||||
emith(" call void @lp_flock()\n")
|
||||
emith(" %vs = load ptr, ptr @lp_visit_set\n")
|
||||
emith(" %vnone = icmp eq ptr %vs, null\n")
|
||||
emith(" br i1 %vnone, label %make, label %clear\n")
|
||||
emith("make:\n")
|
||||
emith(" %v = call ptr @calloc(i64 8388608, i64 8)\n")
|
||||
emith(" store ptr %v, ptr @lp_visit_set\n")
|
||||
emith(" store i64 8388607, ptr @lp_vmask\n")
|
||||
emith(" br label %roots\n")
|
||||
emith("clear:\n")
|
||||
emith(" call ptr @memset(ptr %vs, i32 0, i64 67108864)\n")
|
||||
emith(" br label %roots\n")
|
||||
emith("roots:\n")
|
||||
emith(" store i64 0, ptr @lp_wln\n")
|
||||
emith(" %nr = load i32, ptr @lp_nroots\n")
|
||||
emith(" br label %rl\n")
|
||||
emith("rl:\n")
|
||||
emith(" %ri = phi i32 [ 0, %roots ], [ %ri1, %rb ]\n")
|
||||
emith(" %rgo = icmp ult i32 %ri, %nr\n")
|
||||
emith(" br i1 %rgo, label %rb, label %walk\n")
|
||||
emith("rb:\n")
|
||||
emith(" %rp = getelementptr inbounds ptr, ptr @lp_roots, i32 %ri\n")
|
||||
emith(" %g = load ptr, ptr %rp\n")
|
||||
emith(" %gv = load i64, ptr %g\n")
|
||||
emith(" call void @lp_visit(i64 %gv)\n")
|
||||
emith(" %ri1 = add i32 %ri, 1\n")
|
||||
emith(" br label %rl\n")
|
||||
emith("walk:\n")
|
||||
emith(" %n = load i64, ptr @lp_wln\n")
|
||||
emith(" %done = icmp eq i64 %n, 0\n")
|
||||
emith(" br i1 %done, label %sweep, label %pop\n")
|
||||
emith("pop:\n")
|
||||
emith(" %n1 = sub i64 %n, 1\n")
|
||||
emith(" store i64 %n1, ptr @lp_wln\n")
|
||||
emith(" %wl = load ptr, ptr @lp_wl\n")
|
||||
emith(" %sp = getelementptr inbounds i64, ptr %wl, i64 %n1\n")
|
||||
emith(" %b = load i64, ptr %sp\n")
|
||||
emith(" %bp = inttoptr i64 %b to ptr\n")
|
||||
emith(" %bsz = call i64 @malloc_size(ptr %bp)\n")
|
||||
emith(" %words = lshr i64 %bsz, 3\n")
|
||||
emith(" br label %wordl\n")
|
||||
emith("wordl:\n")
|
||||
emith(" %wi = phi i64 [ 0, %pop ], [ %wi1, %wordb ]\n")
|
||||
emith(" %wgo = icmp ult i64 %wi, %words\n")
|
||||
emith(" br i1 %wgo, label %wordb, label %walk\n")
|
||||
emith("wordb:\n")
|
||||
emith(" %wp = getelementptr inbounds i64, ptr %bp, i64 %wi\n")
|
||||
emith(" %wv = load i64, ptr %wp\n")
|
||||
emith(" call void @lp_visit(i64 %wv)\n")
|
||||
emith(" %wi1 = add i64 %wi, 1\n")
|
||||
emith(" br label %wordl\n")
|
||||
emith("sweep:\n")
|
||||
emith(" %sn = load i32, ptr @lp_site_n\n")
|
||||
emith(" %sn64 = zext i32 %sn to i64\n")
|
||||
emith(" %sb = shl i64 %sn64, 3\n")
|
||||
emith(" call ptr @memset(ptr @lp_site_scan, i32 0, i64 %sb)\n")
|
||||
emith(" %mask = load i64, ptr @lp_tabmask\n")
|
||||
emith(" %cap = add i64 %mask, 1\n")
|
||||
emith(" %tab = load ptr, ptr @lp_tab\n")
|
||||
emith(" br label %tl\n")
|
||||
emith("tl:\n")
|
||||
emith(" %ti = phi i64 [ 0, %sweep ], [ %ti1, %tnext ]\n")
|
||||
emith(" %lost = phi i64 [ 0, %sweep ], [ %lost2, %tnext ]\n")
|
||||
emith(" %lostn = phi i64 [ 0, %sweep ], [ %lostn2, %tnext ]\n")
|
||||
emith(" %tgo = icmp ult i64 %ti, %cap\n")
|
||||
emith(" br i1 %tgo, label %tb, label %report\n")
|
||||
emith("tb:\n")
|
||||
emith(" %e = getelementptr inbounds [2 x i64], ptr %tab, i64 %ti\n")
|
||||
emith(" %ek = load i64, ptr %e\n")
|
||||
emith(" %empty = icmp eq i64 %ek, 0\n")
|
||||
emith(" br i1 %empty, label %tnext, label %tchk\n")
|
||||
emith("tchk:\n")
|
||||
emith(" %seen = call i1 @lp_vhas(i64 %ek)\n")
|
||||
emith(" br i1 %seen, label %tnext, label %tlost\n")
|
||||
emith("tlost:\n")
|
||||
emith(" %ev = getelementptr inbounds i64, ptr %e, i64 1\n")
|
||||
emith(" %val = load i64, ptr %ev\n")
|
||||
emith(" %sz = and i64 %val, 549755813887\n")
|
||||
emith(" %site = lshr i64 %val, 40\n")
|
||||
emith(" %ssp = getelementptr inbounds i64, ptr @lp_site_scan, i64 %site\n")
|
||||
emith(" %sv = load i64, ptr %ssp\n")
|
||||
emith(" %sv1 = add i64 %sv, %sz\n")
|
||||
emith(" store i64 %sv1, ptr %ssp\n")
|
||||
emith(" br label %tnext\n")
|
||||
emith("tnext:\n")
|
||||
emith(" %add = phi i64 [ 0, %tb ], [ 0, %tchk ], [ %sz, %tlost ]\n")
|
||||
emith(" %addn = phi i64 [ 0, %tb ], [ 0, %tchk ], [ 1, %tlost ]\n")
|
||||
emith(" %lost2 = add i64 %lost, %add\n")
|
||||
emith(" %lostn2 = add i64 %lostn, %addn\n")
|
||||
emith(" %ti1 = add i64 %ti, 1\n")
|
||||
emith(" br label %tl\n")
|
||||
emith("report:\n")
|
||||
emith(" store i64 %lost, ptr @lp_scan_bytes\n")
|
||||
emith(" %f = load i64, ptr @lp_frame\n")
|
||||
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_shdr, i64 %f, i64 %lost, i64 %lostn)\n")
|
||||
emith(" br label %rows\n")
|
||||
emith("rows:\n")
|
||||
emith(" %ri2 = phi i32 [ 0, %report ], [ %ri3, %rnext ]\n")
|
||||
emith(" %shown = phi i32 [ 0, %report ], [ %shown2, %rnext ]\n")
|
||||
emith(" %more = icmp ult i32 %ri2, %sn\n")
|
||||
emith(" %room = icmp ult i32 %shown, 24\n")
|
||||
emith(" %rgo2 = and i1 %more, %room\n")
|
||||
emith(" br i1 %rgo2, label %row, label %fin\n")
|
||||
emith("row:\n")
|
||||
emith(" %rsp = getelementptr inbounds i64, ptr @lp_site_scan, i32 %ri2\n")
|
||||
emith(" %rv = load i64, ptr %rsp\n")
|
||||
emith(" %has = icmp sgt i64 %rv, 0\n")
|
||||
emith(" br i1 %has, label %say, label %rnext\n")
|
||||
emith("say:\n")
|
||||
emith(" %fnp = getelementptr inbounds ptr, ptr @lp_site_fn, i32 %ri2\n")
|
||||
emith(" %fn = load ptr, ptr %fnp\n")
|
||||
emith(" %flp = getelementptr inbounds ptr, ptr @lp_site_file, i32 %ri2\n")
|
||||
emith(" %fl = load ptr, ptr %flp\n")
|
||||
emith(" %lnp = getelementptr inbounds i32, ptr @lp_site_line, i32 %ri2\n")
|
||||
emith(" %ln = load i32, ptr %lnp\n")
|
||||
emith(" %kdp = getelementptr inbounds ptr, ptr @lp_site_kind, i32 %ri2\n")
|
||||
emith(" %kd = load ptr, ptr %kdp\n")
|
||||
emith(" call i32 (i32, ptr, ...) @dprintf(i32 2, ptr @.lpf_srow, i64 %rv, ptr %fn, ptr %fl, i32 %ln, ptr %kd)\n")
|
||||
emith(" br label %rnext\n")
|
||||
emith("rnext:\n")
|
||||
emith(" %inc = phi i32 [ 0, %row ], [ 1, %say ]\n")
|
||||
emith(" %shown2 = add i32 %shown, %inc\n")
|
||||
emith(" %ri3 = add i32 %ri2, 1\n")
|
||||
emith(" br label %rows\n")
|
||||
emith("fin:\n")
|
||||
emith(" call void @lp_funlock()\n")
|
||||
emith(" ret i64 %lost\n")
|
||||
emith("}\n")
|
||||
emith("define internal void @lp_fsettle_locked() {\n")
|
||||
emith("entry:\n")
|
||||
emith(" %n = load i32, ptr @lp_site_n\n")
|
||||
|
|
@ -1305,6 +1560,21 @@ function emit_fence_frame() -> void {
|
|||
emith(" br label %tick\n")
|
||||
emith("tick:\n")
|
||||
emith(" store i64 %f1, ptr @lp_frame\n")
|
||||
emith(" %sa = load i64, ptr @lp_scan_at\n")
|
||||
emith(" %sunread = icmp eq i64 %sa, -2\n")
|
||||
emith(" br i1 %sunread, label %sread, label %scheck\n")
|
||||
emith("sread:\n")
|
||||
emith(" %sv = call i64 @lp_fenv(ptr @.lpf_scan, i64 -1)\n")
|
||||
emith(" store i64 %sv, ptr @lp_scan_at\n")
|
||||
emith(" br label %scheck\n")
|
||||
emith("scheck:\n")
|
||||
emith(" %sat = load i64, ptr @lp_scan_at\n")
|
||||
emith(" %sdue = icmp eq i64 %sat, %f1\n")
|
||||
emith(" br i1 %sdue, label %sdo, label %sout\n")
|
||||
emith("sdo:\n")
|
||||
emith(" call i64 @lp_mem_scan()\n")
|
||||
emith(" br label %sout\n")
|
||||
emith("sout:\n")
|
||||
emith(" ret void\n")
|
||||
emith("}\n")
|
||||
}
|
||||
|
|
@ -1356,6 +1626,10 @@ function emit_fence_win() -> void {
|
|||
emith("entry:\n")
|
||||
emith(" ret void\n")
|
||||
emith("}\n")
|
||||
emith("define i64 @lp_mem_scan() {\n")
|
||||
emith("entry:\n")
|
||||
emith(" ret i64 0\n")
|
||||
emith("}\n")
|
||||
}
|
||||
function emit_fence_intern() -> void {
|
||||
emith("@lp_itab = global [65536 x ptr] zeroinitializer\n")
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ function deps_births(f: pointer, seen: []bool) -> void {
|
|||
let c = g_es_site_cls[s]
|
||||
let fi = g_es_site_fn[s]
|
||||
let site = g_es_site[s]
|
||||
if c >= 0 and fi >= 0 and (g_es_flag[c] & ES_ESC) == 0 and not g_es_site_aok[s] and not g_es_site_grow[s] {
|
||||
if c >= 0 and fi >= 0 and (g_es_flag[c] & (ES_ESC | ES_FREED)) == 0 and not g_es_site_aok[s] and not g_es_site_grow[s] {
|
||||
let d = g_es_fnode[fi]
|
||||
let k = dr_index(d.s)
|
||||
let inframe = k >= 0 and seen[k]
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ function emit_header() -> void {
|
|||
j += 1
|
||||
}
|
||||
emith("@g_"); emith(d.s); emith(" = internal global ")
|
||||
if (llty(d.ty) == "ptr") { push(g_scan_roots, d.s) } # 25.5b: where the reachability scan starts
|
||||
emith(llty(d.ty)); emith(" ")
|
||||
emith(global_init(d))
|
||||
emith("\n")
|
||||
|
|
|
|||
73204
selfhost/ludicc.seed.ll
73204
selfhost/ludicc.seed.ll
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue