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:
Orkun ÇAKILKAYA 2026-09-28 15:35:29 +03:00
parent fc0f3d3790
commit a8d54e9878
34 changed files with 106868 additions and 82677 deletions

View file

@ -104,7 +104,7 @@ function emit_crypto_prelude() -> void {
emith(" %ip = alloca i64\n %bp = alloca i64\n")
# padded length = ((len + 8) / 64 + 1) * 64
emith(" %e0 = add i64 %len, 8\n %e1 = lshr i64 %e0, 6\n %e2 = add i64 %e1, 1\n %pl = shl i64 %e2, 6\n")
emith(" %buf = call ptr @malloc(i64 %pl)\n")
emith(" %buf = call ptr @lp_malloc(i64 %pl)\n")
emith(" call ptr @memset(ptr %buf, i32 0, i64 %pl)\n")
emith(" call ptr @memcpy(ptr %buf, ptr %msg, i64 %len)\n")
emith(" %pmark = getelementptr i8, ptr %buf, i64 %len\n store i8 -128, ptr %pmark\n") # 0x80
@ -215,7 +215,7 @@ function emit_crypto_prelude() -> void {
emith(" %ob8 = lshr i32 %hval, 8\n %obb8 = trunc i32 %ob8 to i8\n %oo2 = add i64 %oi4, 2\n %op2 = getelementptr i8, ptr %out, i64 %oo2\n store i8 %obb8, ptr %op2\n")
emith(" %obb0 = trunc i32 %hval to i8\n %oo3 = add i64 %oi4, 3\n %op3 = getelementptr i8, ptr %out, i64 %oo3\n store i8 %obb0, ptr %op3\n")
emith(" %oin = add i64 %oi, 1\n store i64 %oin, ptr %ip\n br label %oc\n")
emith("freeb:\n call void @free(ptr %buf)\n ret void\n}\n")
emith("freeb:\n call void @lp_free(ptr %buf)\n ret void\n}\n")
# one hex digit (0..15) -> its lowercase ASCII byte
emith("define i8 @lp_hex_digit(i32 %d) {\n")
@ -223,7 +223,7 @@ function emit_crypto_prelude() -> void {
# hex-encode %n bytes at %in -> a fresh null-terminated 2n-char string
emith("define ptr @lp_hex_encode(ptr %in, i64 %n) {\n")
emith("entry:\n %ip = alloca i64\n %olen = shl i64 %n, 1\n %olen1 = add i64 %olen, 1\n %s = call ptr @malloc(i64 %olen1)\n store i64 0, ptr %ip\n br label %c\n")
emith("entry:\n %ip = alloca i64\n %olen = shl i64 %n, 1\n %olen1 = add i64 %olen, 1\n %s = call ptr @lp_malloc(i64 %olen1)\n store i64 0, ptr %ip\n br label %c\n")
emith("c:\n %i = load i64, ptr %ip\n %lt = icmp ult i64 %i, %n\n br i1 %lt, label %bdy, label %done\n")
emith("bdy:\n %pp = getelementptr i8, ptr %in, i64 %i\n %byte = load i8, ptr %pp\n %bz = zext i8 %byte to i32\n")
emith(" %hi = lshr i32 %bz, 4\n %lo = and i32 %bz, 15\n %hc = call i8 @lp_hex_digit(i32 %hi)\n %lc = call i8 @lp_hex_digit(i32 %lo)\n")
@ -260,10 +260,10 @@ function emit_crypto_prelude() -> void {
emith("copyk:\n call ptr @memcpy(ptr %k0p, ptr %key, i64 %klen)\n br label %pads\n")
emith("pads:\n")
# inner = SHA-256( (K0 ^ ipad) || msg ), ipad = 0x36
emith(" %inlen = add i64 64, %mlen\n %inbuf = call ptr @malloc(i64 %inlen)\n")
emith(" %inlen = add i64 64, %mlen\n %inbuf = call ptr @lp_malloc(i64 %inlen)\n")
emith(" call void @lp_xor64(ptr %inbuf, ptr %k0p, i32 54)\n")
emith(" %inmsg = getelementptr i8, ptr %inbuf, i64 64\n call ptr @memcpy(ptr %inmsg, ptr %msg, i64 %mlen)\n")
emith(" %innerp = getelementptr [32 x i8], ptr %inner, i64 0, i64 0\n call void @lp_sha256_buf(ptr %inbuf, i64 %inlen, ptr %innerp)\n call void @free(ptr %inbuf)\n")
emith(" %innerp = getelementptr [32 x i8], ptr %inner, i64 0, i64 0\n call void @lp_sha256_buf(ptr %inbuf, i64 %inlen, ptr %innerp)\n call void @lp_free(ptr %inbuf)\n")
# digest = SHA-256( (K0 ^ opad) || inner ), opad = 0x5c
emith(" %outp = getelementptr [96 x i8], ptr %outbuf, i64 0, i64 0\n call void @lp_xor64(ptr %outp, ptr %k0p, i32 92)\n")
emith(" %outmsg = getelementptr i8, ptr %outbuf, i64 64\n call ptr @memcpy(ptr %outmsg, ptr %innerp, i64 32)\n")
@ -318,8 +318,8 @@ function emit_secure_rand_prelude() -> void {
# %n secure bytes -> a fresh 2n-char lowercase hex string
emith("define ptr @lp_random_hex(i64 %n) {\n")
emith("entry:\n %buf = call ptr @malloc(i64 %n)\n call void @lp_secure_bytes(ptr %buf, i64 %n)\n")
emith(" %hex = call ptr @lp_hex_encode(ptr %buf, i64 %n)\n call void @free(ptr %buf)\n ret ptr %hex\n}\n")
emith("entry:\n %buf = call ptr @lp_malloc(i64 %n)\n call void @lp_secure_bytes(ptr %buf, i64 %n)\n")
emith(" %hex = call ptr @lp_hex_encode(ptr %buf, i64 %n)\n call void @lp_free(ptr %buf)\n ret ptr %hex\n}\n")
# one CSPRNG-drawn i32 (little-endian assembly of four secure bytes)
emith("define i32 @lp_random_u32() {\n")
@ -336,8 +336,8 @@ function emit_secure_rand_prelude() -> void {
emith("define ptr @lp_base64(ptr %s) {\n")
emith("entry:\n %n = call i64 @strlen(ptr %s)\n")
emith(" %n2 = add i64 %n, 2\n %grp = udiv i64 %n2, 3\n %bufn = mul i64 %grp, 3\n")
emith(" %olen = mul i64 %grp, 4\n %olen1 = add i64 %olen, 1\n %out = call ptr @malloc(i64 %olen1)\n")
emith(" %inbuf = call ptr @malloc(i64 %bufn)\n call ptr @memset(ptr %inbuf, i32 0, i64 %bufn)\n call ptr @memcpy(ptr %inbuf, ptr %s, i64 %n)\n")
emith(" %olen = mul i64 %grp, 4\n %olen1 = add i64 %olen, 1\n %out = call ptr @lp_malloc(i64 %olen1)\n")
emith(" %inbuf = call ptr @lp_malloc(i64 %bufn)\n call ptr @memset(ptr %inbuf, i32 0, i64 %bufn)\n call ptr @memcpy(ptr %inbuf, ptr %s, i64 %n)\n")
emith(" %gp = alloca i64\n store i64 0, ptr %gp\n br label %cond\n")
emith("cond:\n %gi = load i64, ptr %gp\n %lt = icmp ult i64 %gi, %grp\n br i1 %lt, label %body, label %pad\n")
emith("body:\n %i3 = mul i64 %gi, 3\n")
@ -361,5 +361,5 @@ function emit_secure_rand_prelude() -> void {
emith("pad1:\n %pm1 = sub i64 %olen, 1\n %pp1 = getelementptr i8, ptr %out, i64 %pm1\n store i8 61, ptr %pp1\n %pm2 = sub i64 %olen, 2\n %pp2 = getelementptr i8, ptr %out, i64 %pm2\n store i8 61, ptr %pp2\n br label %done\n")
emith("maybe2:\n br i1 %r2, label %pad2, label %done\n")
emith("pad2:\n %qm1 = sub i64 %olen, 1\n %qp1 = getelementptr i8, ptr %out, i64 %qm1\n store i8 61, ptr %qp1\n br label %done\n")
emith("done:\n call void @free(ptr %inbuf)\n ret ptr %out\n}\n")
emith("done:\n call void @lp_free(ptr %inbuf)\n ret ptr %out\n}\n")
}

View file

@ -384,7 +384,7 @@ function emit_datetime_prelude() -> void {
emith("define ptr @lp_dt_pad0(i32 %v, i32 %w) {\n")
emith(" %we = zext i32 %w to i64\n")
emith(" %sz = add i64 %we, 1\n")
emith(" %buf = call ptr @malloc(i64 %sz)\n")
emith(" %buf = call ptr @lp_malloc(i64 %sz)\n")
emith(" %endp = getelementptr i8, ptr %buf, i32 %w\n")
emith(" store i8 0, ptr %endp\n")
emith(" %kp = alloca i32\n %vp = alloca i32\n")

View file

@ -112,7 +112,7 @@ function emit_fs_prelude() -> void {
function emit_fs_common() -> void {
# duplicate %n bytes of %s into a fresh NUL-terminated buffer
emith("define ptr @lp_fs_dup(ptr %s, i32 %n) {\n")
emith("entry:\n %nz = zext i32 %n to i64\n %t = add i64 %nz, 1\n %m = call ptr @malloc(i64 %t)\n call ptr @memcpy(ptr %m, ptr %s, i64 %nz)\n")
emith("entry:\n %nz = zext i32 %n to i64\n %t = add i64 %nz, 1\n %m = call ptr @lp_malloc(i64 %t)\n call ptr @memcpy(ptr %m, ptr %s, i64 %nz)\n")
emith(" %end = getelementptr i8, ptr %m, i32 %n\n store i8 0, ptr %end\n ret ptr %m\n}\n")
emith("define ptr @lp_fs_strdup(ptr %s) {\n")
@ -142,7 +142,7 @@ function emit_fs_path() -> void {
emith("kb:\n %bemp = icmp eq i32 %lb, 0\n br i1 %bemp, label %reta, label %chk\n")
emith("reta:\n %ra = call ptr @lp_fs_strdup(ptr %a)\n ret ptr %ra\n")
emith("chk:\n %lam1 = sub i32 %la, 1\n %pe = getelementptr i8, ptr %a, i32 %lam1\n %ae = load i8, ptr %pe\n %aei = zext i8 %ae to i32\n %ends = icmp eq i32 %aei, 47\n")
emith(" %sep = select i1 %ends, i32 0, i32 1\n %tot = add i32 %la, %lb\n %tot2 = add i32 %tot, %sep\n %tot3 = add i32 %tot2, 1\n %totz = zext i32 %tot3 to i64\n %m = call ptr @malloc(i64 %totz)\n")
emith(" %sep = select i1 %ends, i32 0, i32 1\n %tot = add i32 %la, %lb\n %tot2 = add i32 %tot, %sep\n %tot3 = add i32 %tot2, 1\n %totz = zext i32 %tot3 to i64\n %m = call ptr @lp_malloc(i64 %totz)\n")
emith(" %laz = zext i32 %la to i64\n call ptr @memcpy(ptr %m, ptr %a, i64 %laz)\n")
# write separator if needed
emith(" br i1 %ends, label %nosep, label %wsep\n")
@ -185,7 +185,7 @@ function emit_fs_path() -> void {
emith("entry:\n %base = call ptr @lp_path_base(ptr %s)\n %ext = call ptr @lp_path_ext(ptr %s)\n")
emith(" %bl64 = call i64 @strlen(ptr %base)\n %bl = trunc i64 %bl64 to i32\n %el64 = call i64 @strlen(ptr %ext)\n %el = trunc i64 %el64 to i32\n")
# the base and the extension are its own copies: freed once the answer is cut out of them
emith(" %keep = sub i32 %bl, %el\n %r = call ptr @lp_fs_dup(ptr %base, i32 %keep)\n call void @free(ptr %base)\n call void @free(ptr %ext)\n ret ptr %r\n}\n")
emith(" %keep = sub i32 %bl, %el\n %r = call ptr @lp_fs_dup(ptr %base, i32 %keep)\n call void @lp_free(ptr %base)\n call void @lp_free(ptr %ext)\n ret ptr %r\n}\n")
emit_fs_normalize()
}
@ -196,9 +196,9 @@ function emit_fs_path() -> void {
function emit_fs_normalize() -> void {
emith("define ptr @lp_path_norm(ptr %s) {\n")
emith("entry:\n %len64 = call i64 @strlen(ptr %s)\n %len = trunc i64 %len64 to i32\n %cap = add i32 %len, 2\n %capz = zext i32 %cap to i64\n")
emith(" %out = call ptr @malloc(i64 %capz)\n")
emith(" %out = call ptr @lp_malloc(i64 %capz)\n")
# segst holds output offsets (i32) of each kept segment's start; size cap ints
emith(" %stz = mul i32 %cap, 4\n %stzz = zext i32 %stz to i64\n %segst = call ptr @malloc(i64 %stzz)\n")
emith(" %stz = mul i32 %cap, 4\n %stzz = zext i32 %stz to i64\n %segst = call ptr @lp_malloc(i64 %stzz)\n")
emith(" %b0 = load i8, ptr %s\n %b0i = zext i8 %b0 to i32\n %abs = icmp eq i32 %b0i, 47\n")
emith(" %ip = alloca i32\n %op = alloca i32\n %scp = alloca i32\n store i32 0, ptr %ip\n store i32 0, ptr %scp\n")
emith(" br i1 %abs, label %ldr, label %noldr\n")
@ -239,8 +239,8 @@ function emit_fs_normalize() -> void {
emith("fdefault:\n br label %term\n")
emith("term:\n %eo = load i32, ptr %op\n %ez = icmp eq i32 %eo, 0\n br i1 %ez, label %emptyout, label %putnul\n")
# the segment table is this call's own: freed on both ways out
emith("emptyout:\n store i8 46, ptr %out\n %e1 = getelementptr i8, ptr %out, i32 1\n store i8 0, ptr %e1\n call void @free(ptr %segst)\n ret ptr %out\n")
emith("putnul:\n %ep = getelementptr i8, ptr %out, i32 %eo\n store i8 0, ptr %ep\n call void @free(ptr %segst)\n ret ptr %out\n}\n")
emith("emptyout:\n store i8 46, ptr %out\n %e1 = getelementptr i8, ptr %out, i32 1\n store i8 0, ptr %e1\n call void @lp_free(ptr %segst)\n ret ptr %out\n")
emith("putnul:\n %ep = getelementptr i8, ptr %out, i32 %eo\n store i8 0, ptr %ep\n call void @lp_free(ptr %segst)\n ret ptr %out\n}\n")
}
# ---- Fs.* (libc) -----------------------------------------------------------
@ -274,7 +274,7 @@ function emit_fs_io() -> void {
emith("entry:\n store i32 0, ptr %lenout\n %f = call ptr @lp_pak_open(ptr %p, ptr @fn_str_rb)\n %nz = icmp ne ptr %f, null\n br i1 %nz, label %ok, label %bad\n")
emith("bad:\n ret ptr null\n")
emith("ok:\n call i32 @fseek(ptr %f, i64 0, i32 2)\n %n64 = call i64 @ftell(ptr %f)\n call i32 @fseek(ptr %f, i64 0, i32 0)\n %n = trunc i64 %n64 to i32\n")
emith(" %cap = add i64 %n64, 1\n %m = call ptr @malloc(i64 %cap)\n %rd = call i64 @fread(ptr %m, i64 1, i64 %n64, ptr %f)\n call i32 @fclose(ptr %f)\n")
emith(" %cap = add i64 %n64, 1\n %m = call ptr @lp_malloc(i64 %cap)\n %rd = call i64 @fread(ptr %m, i64 1, i64 %n64, ptr %f)\n call i32 @fclose(ptr %f)\n")
emith(" %rdi = trunc i64 %rd to i32\n %endp = getelementptr i8, ptr %m, i32 %rdi\n store i8 0, ptr %endp\n store i32 %rdi, ptr %lenout\n ret ptr %m\n}\n")
emith("define ptr @lp_fs_read_text(ptr %p) {\n")
@ -285,14 +285,14 @@ function emit_fs_io() -> void {
emith("define i32 @lp_fs_write_text(ptr %p, ptr %s) {\n")
# the "<p>.tmp" name is this call's own and goes on both ways out
emith("entry:\n %tmp = call ptr @lp_path_join_ext(ptr %p, ptr @fn_str_dottmp)\n %f = call ptr @fopen(ptr %tmp, ptr @fn_str_wb)\n %nz = icmp ne ptr %f, null\n br i1 %nz, label %ok, label %bad\n")
emith("bad:\n call void @free(ptr %tmp)\n ret i32 0\n")
emith("bad:\n call void @lp_free(ptr %tmp)\n ret i32 0\n")
emith("ok:\n %n = call i64 @strlen(ptr %s)\n %w = call i64 @fwrite(ptr %s, i64 1, i64 %n, ptr %f)\n call i32 @fclose(ptr %f)\n")
emith(" %rr = call i32 @rename(ptr %tmp, ptr %p)\n call void @free(ptr %tmp)\n %ok2 = icmp eq i32 %rr, 0\n %z = zext i1 %ok2 to i32\n ret i32 %z\n}\n")
emith(" %rr = call i32 @rename(ptr %tmp, ptr %p)\n call void @lp_free(ptr %tmp)\n %ok2 = icmp eq i32 %rr, 0\n %z = zext i1 %ok2 to i32\n ret i32 %z\n}\n")
# concat two strings (used to build "<p>.tmp"); local so write_text needs no
# dependency on the Os prelude
emith("define ptr @lp_path_join_ext(ptr %a, ptr %b) {\n")
emith("entry:\n %la = call i64 @strlen(ptr %a)\n %lb = call i64 @strlen(ptr %b)\n %sum = add i64 %la, %lb\n %tot = add i64 %sum, 1\n %m = call ptr @malloc(i64 %tot)\n")
emith("entry:\n %la = call i64 @strlen(ptr %a)\n %lb = call i64 @strlen(ptr %b)\n %sum = add i64 %la, %lb\n %tot = add i64 %sum, 1\n %m = call ptr @lp_malloc(i64 %tot)\n")
emith(" call ptr @memcpy(ptr %m, ptr %a, i64 %la)\n %m2 = getelementptr i8, ptr %m, i64 %la\n call ptr @memcpy(ptr %m2, ptr %b, i64 %lb)\n %ep = getelementptr i8, ptr %m, i64 %sum\n store i8 0, ptr %ep\n ret ptr %m\n}\n")
emith("define i32 @lp_fs_append_text(ptr %p, ptr %s) {\n")
@ -309,8 +309,8 @@ function emit_fs_io() -> void {
emith("bad:\n ret i32 0\n")
# the whole file read and the "<dst>.tmp" name are this call's own: both go on every way out
emith("ok:\n %tmp = call ptr @lp_path_join_ext(ptr %dst, ptr @fn_str_dottmp)\n %f = call ptr @fopen(ptr %tmp, ptr @fn_str_wb)\n %fnz = icmp ne ptr %f, null\n br i1 %fnz, label %w, label %badw\n")
emith("badw:\n call void @free(ptr %buf)\n call void @free(ptr %tmp)\n ret i32 0\n")
emith("w:\n %n = load i32, ptr %lp\n %nz64 = zext i32 %n to i64\n call i64 @fwrite(ptr %buf, i64 1, i64 %nz64, ptr %f)\n call i32 @fclose(ptr %f)\n %rr = call i32 @rename(ptr %tmp, ptr %dst)\n call void @free(ptr %buf)\n call void @free(ptr %tmp)\n %ok2 = icmp eq i32 %rr, 0\n %z = zext i1 %ok2 to i32\n ret i32 %z\n}\n")
emith("badw:\n call void @lp_free(ptr %buf)\n call void @lp_free(ptr %tmp)\n ret i32 0\n")
emith("w:\n %n = load i32, ptr %lp\n %nz64 = zext i32 %n to i64\n call i64 @fwrite(ptr %buf, i64 1, i64 %nz64, ptr %f)\n call i32 @fclose(ptr %f)\n %rr = call i32 @rename(ptr %tmp, ptr %dst)\n call void @lp_free(ptr %buf)\n call void @lp_free(ptr %tmp)\n %ok2 = icmp eq i32 %rr, 0\n %z = zext i1 %ok2 to i32\n ret i32 %z\n}\n")
# mkdir: create %p and any missing parents (mkdir -p). Returns 1 if the
# directory exists afterwards. Intermediate EEXIST errors are ignored.
@ -320,7 +320,7 @@ function emit_fs_io() -> void {
emith("go:\n %sl = icmp eq i32 %ci, 47\n br i1 %sl, label %cut, label %nx\n")
emith("cut:\n store i8 0, ptr %pp\n call i32 @mkdir(ptr %dup, i32 493)\n store i8 47, ptr %pp\n br label %nx\n")
emith("nx:\n %i1 = add i32 %i, 1\n store i32 %i1, ptr %ip\n br label %lp\n")
emith("fin:\n call i32 @mkdir(ptr %dup, i32 493)\n call void @free(ptr %dup)\n %r = call i32 @lp_fs_is_dir(ptr %p)\n ret i32 %r\n}\n")
emith("fin:\n call i32 @mkdir(ptr %dup, i32 493)\n call void @lp_free(ptr %dup)\n %r = call i32 @lp_fs_is_dir(ptr %p)\n ret i32 %r\n}\n")
}
# ---- Fs.list (+ sort) ------------------------------------------------------
@ -330,8 +330,8 @@ function emit_fs_dir() -> void {
# the readdir buffer before the next call. macOS/BSD dirent: d_name at offset
# 21 (documented native layout).
emith("define ptr @lp_fs_list(ptr %path) {\n")
emith("entry:\n %h = call ptr @malloc(i64 16)\n %d0 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 0\n %d1 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 1\n %d2 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 2\n")
emith(" %datap = alloca ptr\n %cntp = alloca i32\n %capp = alloca i32\n %init = call ptr @malloc(i64 128)\n store ptr %init, ptr %datap\n store i32 0, ptr %cntp\n store i32 16, ptr %capp\n")
emith("entry:\n %h = call ptr @lp_malloc(i64 16)\n %d0 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 0\n %d1 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 1\n %d2 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 2\n")
emith(" %datap = alloca ptr\n %cntp = alloca i32\n %capp = alloca i32\n %init = call ptr @lp_malloc(i64 128)\n store ptr %init, ptr %datap\n store i32 0, ptr %cntp\n store i32 16, ptr %capp\n")
emith(" %dir = call ptr @opendir(ptr %path)\n %dnz = icmp ne ptr %dir, null\n br i1 %dnz, label %rd, label %empty\n")
emith("rd:\n %de = call ptr @readdir(ptr %dir)\n %denz = icmp ne ptr %de, null\n br i1 %denz, label %ent, label %closed\n")
emith("ent:\n %namep = getelementptr i8, ptr %de, i32 21\n")
@ -343,7 +343,7 @@ function emit_fs_dir() -> void {
emith("keep:\n %nm = call ptr @lp_fs_strdup(ptr %namep)\n")
# grow if full
emith(" %cnt = load i32, ptr %cntp\n %cap = load i32, ptr %capp\n %full = icmp sge i32 %cnt, %cap\n br i1 %full, label %grow, label %put\n")
emith("grow:\n %nc = mul i32 %cap, 2\n store i32 %nc, ptr %capp\n %ncz = zext i32 %nc to i64\n %nb = mul i64 %ncz, 8\n %old = load ptr, ptr %datap\n %new = call ptr @realloc(ptr %old, i64 %nb)\n store ptr %new, ptr %datap\n br label %put\n")
emith("grow:\n %nc = mul i32 %cap, 2\n store i32 %nc, ptr %capp\n %ncz = zext i32 %nc to i64\n %nb = mul i64 %ncz, 8\n %old = load ptr, ptr %datap\n %new = call ptr @lp_realloc(ptr %old, i64 %nb)\n store ptr %new, ptr %datap\n br label %put\n")
emith("put:\n %data = load ptr, ptr %datap\n %cnt2 = load i32, ptr %cntp\n %slot = getelementptr ptr, ptr %data, i32 %cnt2\n store ptr %nm, ptr %slot\n %cnt3 = add i32 %cnt2, 1\n store i32 %cnt3, ptr %cntp\n br label %rd\n")
emith("closed:\n call i32 @closedir(ptr %dir)\n br label %sortit\n")
emith("empty:\n br label %sortit\n")
@ -410,13 +410,13 @@ function emit_fs_mime() -> void {
emith("entry:\n %ext = call ptr @lp_path_ext(ptr %path)\n %lc = call ptr @lp_mime_lc(ptr %ext)\n %ip = alloca i32\n store i32 0, ptr %ip\n br label %lp\n")
emith(`lp:\n %i = load i32, ptr %ip\n %lt = icmp slt i32 %i, {itoa(n)}\n br i1 %lt, label %body, label %def\n`)
emith(`body:\n %kp = getelementptr [{itoa(n)} x {{ ptr, ptr }}], ptr @mime_tbl, i32 0, i32 %i, i32 0\n %k = load ptr, ptr %kp\n %c = call i32 @strcmp(ptr %lc, ptr %k)\n %eq = icmp eq i32 %c, 0\n br i1 %eq, label %hit, label %nx\n`)
emith(`hit:\n %vp = getelementptr [{itoa(n)} x {{ ptr, ptr }}], ptr @mime_tbl, i32 0, i32 %i, i32 1\n %v = load ptr, ptr %vp\n %r = call ptr @lp_fs_strdup(ptr %v)\n call void @free(ptr %ext)\n call void @free(ptr %lc)\n ret ptr %r\n`)
emith(`hit:\n %vp = getelementptr [{itoa(n)} x {{ ptr, ptr }}], ptr @mime_tbl, i32 0, i32 %i, i32 1\n %v = load ptr, ptr %vp\n %r = call ptr @lp_fs_strdup(ptr %v)\n call void @lp_free(ptr %ext)\n call void @lp_free(ptr %lc)\n ret ptr %r\n`)
emith("nx:\n %i1 = add i32 %i, 1\n store i32 %i1, ptr %ip\n br label %lp\n")
emith(`def:\n %d = call ptr @lp_fs_strdup(ptr {k_octet})\n call void @free(ptr %ext)\n call void @free(ptr %lc)\n ret ptr %d\n}}\n`)
emith(`def:\n %d = call ptr @lp_fs_strdup(ptr {k_octet})\n call void @lp_free(ptr %ext)\n call void @lp_free(ptr %lc)\n ret ptr %d\n}}\n`)
# lowercase an extension, dropping a leading '.' (ASCII only, for table lookup)
emith("define ptr @lp_mime_lc(ptr %s) {\n")
emith("entry:\n %l64 = call i64 @strlen(ptr %s)\n %l = trunc i64 %l64 to i32\n %cap = add i64 %l64, 1\n %out = call ptr @malloc(i64 %cap)\n")
emith("entry:\n %l64 = call i64 @strlen(ptr %s)\n %l = trunc i64 %l64 to i32\n %cap = add i64 %l64, 1\n %out = call ptr @lp_malloc(i64 %cap)\n")
emith(" %b0 = load i8, ptr %s\n %b0i = zext i8 %b0 to i32\n %isdot = icmp eq i32 %b0i, 46\n %start = select i1 %isdot, i32 1, i32 0\n")
emith(" %ip = alloca i32\n %op = alloca i32\n store i32 %start, ptr %ip\n store i32 0, ptr %op\n br label %lp\n")
emith("lp:\n %i = load i32, ptr %ip\n %pp = getelementptr i8, ptr %s, i32 %i\n %c = load i8, ptr %pp\n %ci = zext i8 %c to i32\n %z = icmp eq i32 %ci, 0\n br i1 %z, label %done, label %go\n")
@ -431,22 +431,22 @@ function emit_fs_mime() -> void {
function emit_fs_sniff() -> void {
emith("define ptr @lp_mime_sniff(ptr %path) {\n")
emith("entry:\n %f = call ptr @fopen(ptr %path, ptr @fn_str_rb)\n %nz = icmp ne ptr %f, null\n br i1 %nz, label %ok, label %fallback\n")
emith("ok:\n %buf = call ptr @malloc(i64 16)\n %rd = call i64 @fread(ptr %buf, i64 1, i64 8, ptr %f)\n call i32 @fclose(ptr %f)\n %rdi = trunc i64 %rd to i32\n %has4 = icmp sge i32 %rdi, 4\n br i1 %has4, label %chk, label %nomatch\n")
emith("ok:\n %buf = call ptr @lp_malloc(i64 16)\n %rd = call i64 @fread(ptr %buf, i64 1, i64 8, ptr %f)\n call i32 @fclose(ptr %f)\n %rdi = trunc i64 %rd to i32\n %has4 = icmp sge i32 %rdi, 4\n br i1 %has4, label %chk, label %nomatch\n")
emith("chk:\n %b0p = getelementptr i8, ptr %buf, i32 0\n %b0 = load i8, ptr %b0p\n %b0i = zext i8 %b0 to i32\n %b1p = getelementptr i8, ptr %buf, i32 1\n %b1 = load i8, ptr %b1p\n %b1i = zext i8 %b1 to i32\n %b2p = getelementptr i8, ptr %buf, i32 2\n %b2 = load i8, ptr %b2p\n %b2i = zext i8 %b2 to i32\n %b3p = getelementptr i8, ptr %buf, i32 3\n %b3 = load i8, ptr %b3p\n %b3i = zext i8 %b3 to i32\n")
# PNG: 89 50 4E 47
emith(" %p0 = icmp eq i32 %b0i, 137\n %p1 = icmp eq i32 %b1i, 80\n %p2 = icmp eq i32 %b2i, 78\n %p3 = icmp eq i32 %b3i, 71\n %pa = and i1 %p0, %p1\n %pb = and i1 %pa, %p2\n %pc = and i1 %pb, %p3\n br i1 %pc, label %png, label %cj\n")
emith("png:\n %rpng = call ptr @lp_fs_strdup(ptr @fn_sig_png)\n call void @free(ptr %buf)\n ret ptr %rpng\n")
emith("png:\n %rpng = call ptr @lp_fs_strdup(ptr @fn_sig_png)\n call void @lp_free(ptr %buf)\n ret ptr %rpng\n")
# JPEG: FF D8 FF
emith("cj:\n %j0 = icmp eq i32 %b0i, 255\n %j1 = icmp eq i32 %b1i, 216\n %j2 = icmp eq i32 %b2i, 255\n %ja = and i1 %j0, %j1\n %jb = and i1 %ja, %j2\n br i1 %jb, label %jpg, label %cg\n")
emith("jpg:\n %rjpg = call ptr @lp_fs_strdup(ptr @fn_sig_jpg)\n call void @free(ptr %buf)\n ret ptr %rjpg\n")
emith("jpg:\n %rjpg = call ptr @lp_fs_strdup(ptr @fn_sig_jpg)\n call void @lp_free(ptr %buf)\n ret ptr %rjpg\n")
# GIF: 47 49 46
emith("cg:\n %g0 = icmp eq i32 %b0i, 71\n %g1 = icmp eq i32 %b1i, 73\n %g2 = icmp eq i32 %b2i, 70\n %ga = and i1 %g0, %g1\n %gb = and i1 %ga, %g2\n br i1 %gb, label %gif, label %cp\n")
emith("gif:\n %rgif = call ptr @lp_fs_strdup(ptr @fn_sig_gif)\n call void @free(ptr %buf)\n ret ptr %rgif\n")
emith("gif:\n %rgif = call ptr @lp_fs_strdup(ptr @fn_sig_gif)\n call void @lp_free(ptr %buf)\n ret ptr %rgif\n")
# PDF: 25 50 44 46
emith("cp:\n %q0 = icmp eq i32 %b0i, 37\n %q1 = icmp eq i32 %b1i, 80\n %q2 = icmp eq i32 %b2i, 68\n %q3 = icmp eq i32 %b3i, 70\n %qa = and i1 %q0, %q1\n %qb = and i1 %qa, %q2\n %qc = and i1 %qb, %q3\n br i1 %qc, label %pdf, label %nomatch\n")
emith("pdf:\n %rpdf = call ptr @lp_fs_strdup(ptr @fn_sig_pdf)\n call void @free(ptr %buf)\n ret ptr %rpdf\n")
emith("pdf:\n %rpdf = call ptr @lp_fs_strdup(ptr @fn_sig_pdf)\n call void @lp_free(ptr %buf)\n ret ptr %rpdf\n")
# the 16 bytes read are this call's own and go on every way out
emith("nomatch:\n call void @free(ptr %buf)\n br label %fallback\n")
emith("nomatch:\n call void @lp_free(ptr %buf)\n br label %fallback\n")
emith("fallback:\n %r = call ptr @lp_mime_of(ptr %path)\n ret ptr %r\n}\n")
# the small string constants the Fs/Path/Mime runtime references

View file

@ -37,7 +37,7 @@ function list_grow_if_full(h: pointer, elt: pointer) -> void {
let ncw = emit_bind(`zext i32 {nc} to i64`)
let byts = emit_bind(`mul i64 {ncw}, {esz}`)
let old = emit_bind(`load ptr, ptr {dp}`)
let nd = emit_bind(`call ptr @realloc(ptr {old}, i64 {byts})`)
let nd = emit_bind(`call ptr @lp_realloc(ptr {old}, i64 {byts})`)
emit(" store ptr "); emit(nd); emit(", ptr "); emit(dp); emit("\n")
emit(" store i32 "); emit(nc); emit(", ptr "); emit(cp); emit("\n")
emit(" br label %"); emit(done); emit("\n")
@ -93,7 +93,7 @@ function emit_merge_sort(h: pointer, elt: pointer, mode: int, fnsym: pointer, ke
let esz = emit_sizeof(elt)
let nz = emit_bind(`zext i32 {n} to i64`)
let byts = emit_bind(`mul i64 {nz}, {esz}`)
let scratch = emit_bind(`call ptr @malloc(i64 {byts})`)
let scratch = emit_bind(`call ptr @lp_malloc(i64 {byts})`)
# outer: for (width = 1; width < n; width *= 2)
let wp = emit_alloca("i32"); store_at("i32", "1", wp)
@ -212,7 +212,7 @@ function emit_merge_sort(h: pointer, elt: pointer, mode: int, fnsym: pointer, ke
store_at("i32", w2, wp) # width *= 2
emit(" br label %"); emit(wc); emit("\n")
emit(we); emit(":\n")
emit(" call void @free(ptr "); emit(scratch); emit(")\n")
emit(" call void @lp_free(ptr "); emit(scratch); emit(")\n")
}
# resolve a sort_by/sort_with function argument (a bare identifier naming a

View file

@ -82,7 +82,7 @@ function emit_log_ns(meth: pointer, e: Node) -> Val {
i += 2
}
emit(` call void @lp_log_emit(i32 {lvl}, ptr {line.code})\n`)
emit(` call void @free(ptr {line.code})\n`)
emit(` call void @lp_free(ptr {line.code})\n`)
emit(` br label %{lend}\n`)
emit(`{lend}:\n`)
return val("0", "void")

View file

@ -164,13 +164,13 @@ function emit_os_prelude() -> void {
# concatenate two NUL-terminated strings into a fresh malloc'd buffer
emith("define ptr @lp_os_join2(ptr %a, ptr %b) {\n")
emith("entry:\n %la = call i64 @strlen(ptr %a)\n %lb = call i64 @strlen(ptr %b)\n")
emith(" %sum = add i64 %la, %lb\n %tot = add i64 %sum, 1\n %m = call ptr @malloc(i64 %tot)\n")
emith(" %sum = add i64 %la, %lb\n %tot = add i64 %sum, 1\n %m = call ptr @lp_malloc(i64 %tot)\n")
emith(" call ptr @memcpy(ptr %m, ptr %a, i64 %la)\n")
emith(" %m2 = getelementptr i8, ptr %m, i64 %la\n call ptr @memcpy(ptr %m2, ptr %b, i64 %lb)\n")
emith(" %end = getelementptr i8, ptr %m, i64 %sum\n store i8 0, ptr %end\n ret ptr %m\n}\n")
emith("define ptr @lp_os_join3(ptr %a, ptr %b, ptr %c) {\n")
emith("entry:\n %ab = call ptr @lp_os_join2(ptr %a, ptr %b)\n %r = call ptr @lp_os_join2(ptr %ab, ptr %c)\n call void @free(ptr %ab)\n ret ptr %r\n}\n")
emith("entry:\n %ab = call ptr @lp_os_join2(ptr %a, ptr %b)\n %r = call ptr @lp_os_join2(ptr %ab, ptr %c)\n call void @lp_free(ptr %ab)\n ret ptr %r\n}\n")
# Windows has its own known folders and no uname; emit_win.ludic supplies them
if g_target_win { emit_os_win_known(k_dot, k_slash); return }
@ -204,9 +204,9 @@ function emit_os_prelude() -> void {
emith("define i32 @lp_os_is_darwin() {\n")
emith("entry:\n %c = load i32, ptr @L_os_darwin\n %known = icmp sge i32 %c, 0\n br i1 %known, label %done, label %probe\n")
emith("done:\n ret i32 %c\n")
emith("probe:\n %buf = call ptr @malloc(i64 8192)\n call i32 @uname(ptr %buf)\n")
emith("probe:\n %buf = call ptr @lp_malloc(i64 8192)\n call i32 @uname(ptr %buf)\n")
emith(` %cd = call i32 @strncmp(ptr %buf, ptr {k_darw}, i64 6)\n %isd = icmp eq i32 %cd, 0\n`)
emith(" %r = select i1 %isd, i32 1, i32 0\n call void @free(ptr %buf)\n store i32 %r, ptr @L_os_darwin\n ret i32 %r\n}\n")
emith(" %r = select i1 %isd, i32 1, i32 0\n call void @lp_free(ptr %buf)\n store i32 %r, ptr @L_os_darwin\n ret i32 %r\n}\n")
# $<var> when it is set and non-empty, else $HOME<rel>; the result always ends in '/'
emith("define ptr @lp_os_xdg(ptr %var, ptr %rel) {\n")
@ -219,7 +219,7 @@ function emit_os_prelude() -> void {
emith("define ptr @lp_os_known(ptr %app, ptr %mac, ptr %var, ptr %rel) {\n")
emith("entry:\n %d = call i32 @lp_os_is_darwin()\n %isd = icmp ne i32 %d, 0\n br i1 %isd, label %m, label %x\n")
emith("m:\n %h = call ptr @lp_os_home()\n %r1 = call ptr @lp_os_join3(ptr %h, ptr %mac, ptr %app)\n ret ptr %r1\n")
emith("x:\n %b = call ptr @lp_os_xdg(ptr %var, ptr %rel)\n %r2 = call ptr @lp_os_join2(ptr %b, ptr %app)\n call void @free(ptr %b)\n ret ptr %r2\n}\n")
emith("x:\n %b = call ptr @lp_os_xdg(ptr %var, ptr %rel)\n %r2 = call ptr @lp_os_join2(ptr %b, ptr %app)\n call void @lp_free(ptr %b)\n ret ptr %r2\n}\n")
emith(`define ptr @lp_os_save_dir(ptr %app) {{\n %r = call ptr @lp_os_known(ptr %app, ptr {k_appsp}, ptr {k_xdg_data}, ptr {k_dot_share})\n ret ptr %r\n}}\n`)
emith(`define ptr @lp_os_config_dir(ptr %app) {{\n %r = call ptr @lp_os_known(ptr %app, ptr {k_appsp}, ptr {k_xdg_cfg}, ptr {k_dot_config})\n ret ptr %r\n}}\n`)
@ -230,7 +230,7 @@ function emit_os_prelude() -> void {
# snapshot the caller may iterate or index like any other []string.
emith("define ptr @lp_os_args() {\n")
emith("entry:\n %c = load i32, ptr @L_argc\n %v = load ptr, ptr @L_argv\n")
emith(" %h = call ptr @malloc(i64 16)\n")
emith(" %h = call ptr @lp_malloc(i64 16)\n")
emith(" %d0 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 0\n store ptr %v, ptr %d0\n")
emith(" %d1 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 1\n store i32 %c, ptr %d1\n")
emith(" %d2 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 2\n store i32 %c, ptr %d2\n")
@ -242,7 +242,7 @@ function emit_os_prelude() -> void {
emith("define ptr @lp_os_uts() {\n")
emith("entry:\n %c = load ptr, ptr @L_os_uts\n %have = icmp ne ptr %c, null\n br i1 %have, label %done, label %make\n")
emith("done:\n ret ptr %c\n")
emith("make:\n %buf = call ptr @malloc(i64 8192)\n call i32 @uname(ptr %buf)\n store ptr %buf, ptr @L_os_uts\n ret ptr %buf\n}\n")
emith("make:\n %buf = call ptr @lp_malloc(i64 8192)\n call i32 @uname(ptr %buf)\n store ptr %buf, ptr @L_os_uts\n ret ptr %buf\n}\n")
# platform(): uname sysname (field 0, portable) mapped to a short id
emith("define ptr @lp_os_platform() {\n")

View file

@ -234,7 +234,7 @@ function emit_pak_boot() -> void {
emith("define ptr @lp_pak_slurp(ptr %path) {\n")
emith("entry:\n %f = call ptr @fopen(ptr %path, ptr @.pak_rb)\n %bad = icmp eq ptr %f, null\n br i1 %bad, label %no, label %go\n")
emith("go:\n %s1 = call i32 @fseek(ptr %f, i64 0, i32 2)\n %n64 = call i64 @ftell(ptr %f)\n %s2 = call i32 @fseek(ptr %f, i64 0, i32 0)\n")
emith(" %cap = add i64 %n64, 1\n %buf = call ptr @malloc(i64 %cap)\n %rd = call i64 @fread(ptr %buf, i64 1, i64 %n64, ptr %f)\n")
emith(" %cap = add i64 %n64, 1\n %buf = call ptr @lp_malloc(i64 %cap)\n %rd = call i64 @fread(ptr %buf, i64 1, i64 %n64, ptr %f)\n")
emith(" %e = getelementptr i8, ptr %buf, i64 %rd\n store i8 0, ptr %e\n %c = call i32 @fclose(ptr %f)\n ret ptr %buf\n")
emith("no:\n ret ptr null\n}\n")
@ -324,9 +324,9 @@ function emit_pak_boot() -> void {
emith("entry:\n %f = call ptr @lp_pak_open(ptr %path, ptr @.pak_rb)\n %bad = icmp eq ptr %f, null\n br i1 %bad, label %out, label %go\n")
emith("go:\n %s1 = call i32 @fseek(ptr %f, i64 0, i32 2)\n %n64 = call i64 @ftell(ptr %f)\n %s2 = call i32 @fseek(ptr %f, i64 0, i32 0)\n")
emith(" %tiny = icmp sle i64 %n64, 0\n br i1 %tiny, label %shut, label %read\n")
emith("read:\n %buf = call ptr @malloc(i64 %n64)\n %rd = call i64 @fread(ptr %buf, i64 1, i64 %n64, ptr %f)\n")
emith("read:\n %buf = call ptr @lp_malloc(i64 %n64)\n %rd = call i64 @fread(ptr %buf, i64 1, i64 %n64, ptr %f)\n")
emith(" %c1 = call i32 @fclose(ptr %f)\n %n32 = trunc i64 %rd to i32\n")
emith(" call void @app_set_icon(ptr %buf, i32 %n32)\n call void @free(ptr %buf)\n ret void\n")
emith(" call void @app_set_icon(ptr %buf, i32 %n32)\n call void @lp_free(ptr %buf)\n ret void\n")
emith("shut:\n %c2 = call i32 @fclose(ptr %f)\n ret void\n")
emith("out:\n ret void\n}\n")
}

View file

@ -19,7 +19,7 @@ function is_text_ns(meth: pointer) -> bool {
# read: Text.to_int(string(n)) kept n's text. Every string a Text call returns is a copy of its own,
# so it is fresh and goes once a +, == or print has read it.
function text_gone(v: Val) -> void {
if v.fresh { emit(` call void @free(ptr {v.code})\n`) }
if v.fresh { emit(` call void @lp_free(ptr {v.code})\n`) }
}
function emit_text_ns(meth: pointer, e: Node) -> Val {

View file

@ -7,7 +7,7 @@ function emit_text_prelude() -> void {
emith("entry:\n")
emith(" %n = call i64 @strlen(ptr %s)\n")
emith(" %sz = add i64 %n, 1\n")
emith(" %out = call ptr @malloc(i64 %sz)\n")
emith(" %out = call ptr @lp_malloc(i64 %sz)\n")
emith(" %ip = alloca i64\n")
emith(" store i64 0, ptr %ip\n")
emith(" br label %cond\n")
@ -37,7 +37,7 @@ function emit_text_prelude() -> void {
emith("entry:\n")
emith(" %n = call i64 @strlen(ptr %s)\n")
emith(" %sz = add i64 %n, 1\n")
emith(" %out = call ptr @malloc(i64 %sz)\n")
emith(" %out = call ptr @lp_malloc(i64 %sz)\n")
emith(" %ip = alloca i64\n")
emith(" store i64 0, ptr %ip\n")
emith(" br label %cond\n")
@ -104,7 +104,7 @@ function emit_text_prelude() -> void {
emith(" %en = load i64, ptr %ep\n")
emith(" %len = sub i64 %en, %st\n")
emith(" %sz = add i64 %len, 1\n")
emith(" %out = call ptr @malloc(i64 %sz)\n")
emith(" %out = call ptr @lp_malloc(i64 %sz)\n")
emith(" %src = getelementptr i8, ptr %s, i64 %st\n")
emith(" call ptr @memcpy(ptr %out, ptr %src, i64 %len)\n")
emith(" %tp = getelementptr i8, ptr %out, i64 %len\n")
@ -129,7 +129,7 @@ function emit_text_prelude() -> void {
emith(" %L = call i64 @strlen(ptr %s)\n")
emith(" %tot = mul i64 %L, %n\n")
emith(" %sz = add i64 %tot, 1\n")
emith(" %out = call ptr @malloc(i64 %sz)\n")
emith(" %out = call ptr @lp_malloc(i64 %sz)\n")
emith(" %ip = alloca i64\n")
emith(" store i64 0, ptr %ip\n")
emith(" br label %cond\n")
@ -157,7 +157,7 @@ function emit_text_prelude() -> void {
emith(" br i1 %need, label %do, label %copy\n")
emith("copy:\n")
emith(" %sz0 = add i64 %L, 1\n")
emith(" %o0 = call ptr @malloc(i64 %sz0)\n")
emith(" %o0 = call ptr @lp_malloc(i64 %sz0)\n")
emith(" %e0 = add i64 %L, 0\n")
emith(" call ptr @memcpy(ptr %o0, ptr %s, i64 %L)\n")
emith(" %t0 = getelementptr i8, ptr %o0, i64 %L\n")
@ -166,7 +166,7 @@ function emit_text_prelude() -> void {
emith("do:\n")
emith(" %pad = sub i64 %w0, %L\n")
emith(" %sz = add i64 %w0, 1\n")
emith(" %out = call ptr @malloc(i64 %sz)\n")
emith(" %out = call ptr @lp_malloc(i64 %sz)\n")
emith(" br i1 %left, label %padleft, label %padright\n")
emith("padleft:\n")
emith(" call void @lp_fill_sp(ptr %out, i64 0, i64 %pad)\n")
@ -216,7 +216,7 @@ function emit_text2_prelude() -> void {
emith("copyall:\n")
emith(" %ls0 = call i64 @strlen(ptr %s)\n")
emith(" %sz0 = add i64 %ls0, 1\n")
emith(" %o0 = call ptr @malloc(i64 %sz0)\n")
emith(" %o0 = call ptr @lp_malloc(i64 %sz0)\n")
emith(" call ptr @memcpy(ptr %o0, ptr %s, i64 %sz0)\n")
emith(" ret ptr %o0\n")
emith("scan:\n")
@ -245,7 +245,7 @@ function emit_text2_prelude() -> void {
emith(" %grow = mul i64 %cnt, %delta\n")
emith(" %newlen = add i64 %ls, %grow\n")
emith(" %osz = add i64 %newlen, 1\n")
emith(" %out = call ptr @malloc(i64 %osz)\n")
emith(" %out = call ptr @lp_malloc(i64 %osz)\n")
emith(" %srcp = alloca ptr\n")
emith(" store ptr %s, ptr %srcp\n")
emith(" %dstp = alloca ptr\n")
@ -312,7 +312,7 @@ function emit_text2_prelude() -> void {
emith(" %tot0 = load i64, ptr %totp\n")
emith(" %tot = add i64 %tot0, %sepsz\n")
emith(" %osz = add i64 %tot, 1\n")
emith(" %out = call ptr @malloc(i64 %osz)\n")
emith(" %out = call ptr @lp_malloc(i64 %osz)\n")
emith(" %dstp = alloca ptr\n")
emith(" store ptr %out, ptr %dstp\n")
emith(" %jp = alloca i64\n")
@ -369,9 +369,9 @@ function emit_text2_prelude() -> void {
emith(" br label %ccond\n")
emith("mk:\n")
emith(" %cnt = load i64, ptr %cntp\n")
emith(" %hdr = call ptr @malloc(i64 16)\n")
emith(" %hdr = call ptr @lp_malloc(i64 16)\n")
emith(" %arrsz = mul i64 %cnt, 8\n")
emith(" %arr = call ptr @malloc(i64 %arrsz)\n")
emith(" %arr = call ptr @lp_malloc(i64 %arrsz)\n")
emith(" %d0 = getelementptr inbounds %LSlice, ptr %hdr, i32 0, i32 0\n")
emith(" store ptr %arr, ptr %d0\n")
emith(" %cnt32 = trunc i64 %cnt to i32\n")
@ -404,7 +404,7 @@ function emit_text2_prelude() -> void {
emith("store:\n")
emith(" %seg = phi i64 [ %seglen, %mid ], [ %rem, %last ]\n")
emith(" %ssz = add i64 %seg, 1\n")
emith(" %sub = call ptr @malloc(i64 %ssz)\n")
emith(" %sub = call ptr @lp_malloc(i64 %ssz)\n")
emith(" %src2 = load ptr, ptr %srcp\n")
emith(" call ptr @memcpy(ptr %sub, ptr %src2, i64 %seg)\n")
emith(" %tp = getelementptr i8, ptr %sub, i64 %seg\n")

View file

@ -248,8 +248,8 @@ function emit_uni_str_fns() -> void {
# chars(s) -> []int : a fresh %LSlice of every code point, in order
emith("define ptr @lp_uni_chars(ptr %s) {\n")
emith("entry:\n %n = call i32 @lp_uni_len(ptr %s)\n %h = call ptr @malloc(i64 16)\n")
emith(" %nz = zext i32 %n to i64\n %bytes = mul i64 %nz, 4\n %data = call ptr @malloc(i64 %bytes)\n")
emith("entry:\n %n = call i32 @lp_uni_len(ptr %s)\n %h = call ptr @lp_malloc(i64 16)\n")
emith(" %nz = zext i32 %n to i64\n %bytes = mul i64 %nz, 4\n %data = call ptr @lp_malloc(i64 %bytes)\n")
emith(" %d0 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 0\n store ptr %data, ptr %d0\n")
emith(" %d1 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 1\n store i32 %n, ptr %d1\n")
emith(" %d2 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 2\n store i32 %n, ptr %d2\n")
@ -264,7 +264,7 @@ function emit_uni_str_fns() -> void {
# maps each code point, and re-encodes into a fresh buffer (worst case 4 bytes
# per code point, though ASCII/Latin-1 mapping preserves byte length).
emith("define ptr @lp_uni_case(ptr %s, i32 %up) {\n")
emith("entry:\n %bl = call i64 @strlen(ptr %s)\n %cap0 = mul i64 %bl, 4\n %cap = add i64 %cap0, 4\n %out = call ptr @malloc(i64 %cap)\n")
emith("entry:\n %bl = call i64 @strlen(ptr %s)\n %cap0 = mul i64 %bl, 4\n %cap = add i64 %cap0, 4\n %out = call ptr @lp_malloc(i64 %cap)\n")
emith(" %ip = alloca i32\n %op = alloca i32\n %cp = alloca i32\n store i32 0, ptr %ip\n store i32 0, ptr %op\n br label %lp\n")
emith("lp:\n %i = load i32, ptr %ip\n %p = getelementptr i8, ptr %s, i32 %i\n %b = load i8, ptr %p\n %c = zext i8 %b to i32\n")
emith(" %z = icmp eq i32 %c, 0\n br i1 %z, label %done, label %go\n")
@ -281,7 +281,7 @@ function emit_uni_str_fns() -> void {
emith("chk:\n %i = load i32, ptr %ip\n %p = getelementptr i8, ptr %s, i32 %i\n %b = load i8, ptr %p\n %c = zext i8 %b to i32\n")
emith(" %z = icmp eq i32 %c, 0\n br i1 %z, label %cut, label %go\n")
emith("go:\n %ni = call i32 @lp_uni_decode(ptr %s, i32 %i, ptr %cp)\n %k1 = add i32 %k, 1\n store i32 %k1, ptr %kp\n store i32 %ni, ptr %ip\n br label %lp\n")
emith("cut:\n %len = load i32, ptr %ip\n %lz = zext i32 %len to i64\n %cap = add i64 %lz, 1\n %out = call ptr @malloc(i64 %cap)\n %lz2 = zext i32 %len to i64\n call ptr @memcpy(ptr %out, ptr %s, i64 %lz2)\n")
emith("cut:\n %len = load i32, ptr %ip\n %lz = zext i32 %len to i64\n %cap = add i64 %lz, 1\n %out = call ptr @lp_malloc(i64 %cap)\n %lz2 = zext i32 %len to i64\n call ptr @memcpy(ptr %out, ptr %s, i64 %lz2)\n")
emith(" %endp = getelementptr i8, ptr %out, i32 %len\n store i8 0, ptr %endp\n ret ptr %out\n}\n")
emit_uni_grapheme()

View file

@ -72,7 +72,7 @@ function emit_uuid_prelude() -> void {
# 16 raw bytes -> a fresh canonical 36-char string. hex-encode all 16 bytes,
# then splice the four hyphens between the 8/4/4/4/12 groups.
emith("define ptr @lp_uuid_format(ptr %b16) {\n")
emith("entry:\n %hex = call ptr @lp_hex_encode(ptr %b16, i64 16)\n %out = call ptr @malloc(i64 37)\n")
emith("entry:\n %hex = call ptr @lp_hex_encode(ptr %b16, i64 16)\n %out = call ptr @lp_malloc(i64 37)\n")
emith(" call ptr @memcpy(ptr %out, ptr %hex, i64 8)\n")
emith(" %o8 = getelementptr i8, ptr %out, i64 8\n store i8 45, ptr %o8\n")
emith(" %h8 = getelementptr i8, ptr %hex, i64 8\n %o9 = getelementptr i8, ptr %out, i64 9\n call ptr @memcpy(ptr %o9, ptr %h8, i64 4)\n")
@ -83,7 +83,7 @@ function emit_uuid_prelude() -> void {
emith(" %o23 = getelementptr i8, ptr %out, i64 23\n store i8 45, ptr %o23\n")
emith(" %h20 = getelementptr i8, ptr %hex, i64 20\n %o24 = getelementptr i8, ptr %out, i64 24\n call ptr @memcpy(ptr %o24, ptr %h20, i64 12)\n")
emith(" %o36 = getelementptr i8, ptr %out, i64 36\n store i8 0, ptr %o36\n")
emith(" call void @free(ptr %hex)\n ret ptr %out\n}\n")
emith(" call void @lp_free(ptr %hex)\n ret ptr %out\n}\n")
# v4: 16 CSPRNG bytes, then set version (0x4x in byte 6) and variant (0b10xx in
# byte 8). 0x80 does not fit an i8 immediate, so it is written as -128.
@ -112,7 +112,7 @@ function emit_uuid_prelude() -> void {
# the nil UUID: 36 '0' with hyphens spliced in
emith("define ptr @lp_uuid_nil() {\n")
emith("entry:\n %out = call ptr @malloc(i64 37)\n call ptr @memset(ptr %out, i32 48, i64 36)\n")
emith("entry:\n %out = call ptr @lp_malloc(i64 37)\n call ptr @memset(ptr %out, i32 48, i64 36)\n")
emith(" %o8 = getelementptr i8, ptr %out, i64 8\n store i8 45, ptr %o8\n")
emith(" %o13 = getelementptr i8, ptr %out, i64 13\n store i8 45, ptr %o13\n")
emith(" %o18 = getelementptr i8, ptr %out, i64 18\n store i8 45, ptr %o18\n")
@ -153,7 +153,7 @@ function emit_uuid_prelude() -> void {
# parse: lowercase-normalise a valid UUID, else return the nil UUID.
emith("define ptr @lp_uuid_parse(ptr %s) {\n")
emith("entry:\n %ok = call i32 @lp_uuid_valid(ptr %s)\n %isok = icmp ne i32 %ok, 0\n br i1 %isok, label %dup, label %nilb\n")
emith("dup:\n %out = call ptr @malloc(i64 37)\n %ip = alloca i64\n store i64 0, ptr %ip\n br label %cond\n")
emith("dup:\n %out = call ptr @lp_malloc(i64 37)\n %ip = alloca i64\n store i64 0, ptr %ip\n br label %cond\n")
emith("cond:\n %i = load i64, ptr %ip\n %lt = icmp ult i64 %i, 36\n br i1 %lt, label %body, label %fin\n")
emith("body:\n %p = getelementptr i8, ptr %s, i64 %i\n %c = load i8, ptr %p\n")
emith(" %cA = icmp uge i8 %c, 65\n %cZ = icmp ule i8 %c, 90\n %cup = and i1 %cA, %cZ\n %c32 = add i8 %c, 32\n %cl = select i1 %cup, i8 %c32, i8 %c\n")

View file

@ -146,11 +146,11 @@ function emit_win_files() -> void {
# returns block + 39 so that d_name, read at +21, is cFileName itself.
function emit_win_dirs() -> void {
emith("define internal ptr @opendir(ptr %path) {\n")
emith("entry:\n %l = call i64 @strlen(ptr %path)\n %cap = add i64 %l, 3\n %pat = call ptr @malloc(i64 %cap)\n call ptr @memcpy(ptr %pat, ptr %path, i64 %l)\n")
emith("entry:\n %l = call i64 @strlen(ptr %path)\n %cap = add i64 %l, 3\n %pat = call ptr @lp_malloc(i64 %cap)\n call ptr @memcpy(ptr %pat, ptr %path, i64 %l)\n")
emith(" %e0 = getelementptr i8, ptr %pat, i64 %l\n store i8 47, ptr %e0\n %e1 = getelementptr i8, ptr %e0, i64 1\n store i8 42, ptr %e1\n %e2 = getelementptr i8, ptr %e0, i64 2\n store i8 0, ptr %e2\n")
emith(" %d = call ptr @malloc(i64 368)\n %fd = getelementptr i8, ptr %d, i64 16\n %h = call ptr @FindFirstFileA(ptr %pat, ptr %fd)\n call void @free(ptr %pat)\n")
emith(" %d = call ptr @lp_malloc(i64 368)\n %fd = getelementptr i8, ptr %d, i64 16\n %h = call ptr @FindFirstFileA(ptr %pat, ptr %fd)\n call void @lp_free(ptr %pat)\n")
emith(" %bad = icmp eq ptr %h, inttoptr (i64 -1 to ptr)\n br i1 %bad, label %no, label %ok\n")
emith("no:\n call void @free(ptr %d)\n ret ptr null\n")
emith("no:\n call void @lp_free(ptr %d)\n ret ptr null\n")
emith("ok:\n store ptr %h, ptr %d\n %fl = getelementptr i8, ptr %d, i64 8\n store i32 1, ptr %fl\n ret ptr %d\n}\n")
emith("define internal ptr @readdir(ptr %d) {\n")
@ -160,7 +160,7 @@ function emit_win_dirs() -> void {
emith("give:\n %de = getelementptr i8, ptr %d, i64 39\n ret ptr %de\n")
emith("end:\n ret ptr null\n}\n")
emith("define internal i32 @closedir(ptr %d) {\nentry:\n %h = load ptr, ptr %d\n %r = call i32 @FindClose(ptr %h)\n call void @free(ptr %d)\n ret i32 0\n}\n")
emith("define internal i32 @closedir(ptr %d) {\nentry:\n %h = load ptr, ptr %d\n %r = call i32 @FindClose(ptr %h)\n call void @lp_free(ptr %d)\n ret i32 0\n}\n")
}
# ---- mapped files and memory streams -------------------------------------------
@ -247,7 +247,7 @@ function emit_os_win_known(k_dot: pointer, k_slash: pointer) -> void {
# Os.args(), as emit_os_prelude defines it
emith("define ptr @lp_os_args() {\n")
emith("entry:\n %c = load i32, ptr @L_argc\n %v = load ptr, ptr @L_argv\n")
emith(" %h = call ptr @malloc(i64 16)\n")
emith(" %h = call ptr @lp_malloc(i64 16)\n")
emith(" %d0 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 0\n store ptr %v, ptr %d0\n")
emith(" %d1 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 1\n store i32 %c, ptr %d1\n")
emith(" %d2 = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 2\n store i32 %c, ptr %d2\n")