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>
422 lines
16 KiB
Text
422 lines
16 KiB
Text
# emit_text_prelude.ludic — the emitted Text runtime prelude: the string-builder helpers (upper/lower/trim/repeat/pad and the split/join machinery) written into each program that uses Text.*. Split out of emit_text.ludic (concern: emitted runtime code, vs. emit_text.ludic's Text.* namespace dispatch).
|
|
# emit_text_prelude — string builders that allocate: upper/lower/trim/
|
|
# repeat/pad. Emitted once per program that uses them (g_uses_textrt). Plain
|
|
# libc (strlen/malloc/memcpy), deterministic, C-string in and out.
|
|
function emit_text_prelude() -> void {
|
|
emith("define ptr @lp_str_upper(ptr %s) {\n")
|
|
emith("entry:\n")
|
|
emith(" %n = call i64 @strlen(ptr %s)\n")
|
|
emith(" %sz = add i64 %n, 1\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")
|
|
emith("cond:\n")
|
|
emith(" %i = load i64, ptr %ip\n")
|
|
emith(" %d = icmp ult i64 %i, %n\n")
|
|
emith(" br i1 %d, label %body, label %fin\n")
|
|
emith("body:\n")
|
|
emith(" %sp = getelementptr i8, ptr %s, i64 %i\n")
|
|
emith(" %c = load i8, ptr %sp\n")
|
|
emith(" %ge = icmp uge i8 %c, 97\n")
|
|
emith(" %le = icmp ule i8 %c, 122\n")
|
|
emith(" %in = and i1 %ge, %le\n")
|
|
emith(" %cc = add i8 %c, -32\n")
|
|
emith(" %oc = select i1 %in, i8 %cc, i8 %c\n")
|
|
emith(" %op = getelementptr i8, ptr %out, i64 %i\n")
|
|
emith(" store i8 %oc, ptr %op\n")
|
|
emith(" %i1 = add i64 %i, 1\n")
|
|
emith(" store i64 %i1, ptr %ip\n")
|
|
emith(" br label %cond\n")
|
|
emith("fin:\n")
|
|
emith(" %tp = getelementptr i8, ptr %out, i64 %n\n")
|
|
emith(" store i8 0, ptr %tp\n")
|
|
emith(" ret ptr %out\n")
|
|
emith("}\n")
|
|
emith("define ptr @lp_str_lower(ptr %s) {\n")
|
|
emith("entry:\n")
|
|
emith(" %n = call i64 @strlen(ptr %s)\n")
|
|
emith(" %sz = add i64 %n, 1\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")
|
|
emith("cond:\n")
|
|
emith(" %i = load i64, ptr %ip\n")
|
|
emith(" %d = icmp ult i64 %i, %n\n")
|
|
emith(" br i1 %d, label %body, label %fin\n")
|
|
emith("body:\n")
|
|
emith(" %sp = getelementptr i8, ptr %s, i64 %i\n")
|
|
emith(" %c = load i8, ptr %sp\n")
|
|
emith(" %ge = icmp uge i8 %c, 65\n")
|
|
emith(" %le = icmp ule i8 %c, 90\n")
|
|
emith(" %in = and i1 %ge, %le\n")
|
|
emith(" %cc = add i8 %c, 32\n")
|
|
emith(" %oc = select i1 %in, i8 %cc, i8 %c\n")
|
|
emith(" %op = getelementptr i8, ptr %out, i64 %i\n")
|
|
emith(" store i8 %oc, ptr %op\n")
|
|
emith(" %i1 = add i64 %i, 1\n")
|
|
emith(" store i64 %i1, ptr %ip\n")
|
|
emith(" br label %cond\n")
|
|
emith("fin:\n")
|
|
emith(" %tp = getelementptr i8, ptr %out, i64 %n\n")
|
|
emith(" store i8 0, ptr %tp\n")
|
|
emith(" ret ptr %out\n")
|
|
emith("}\n")
|
|
emith("define ptr @lp_str_trim(ptr %s) {\n")
|
|
emith("entry:\n")
|
|
emith(" %n = call i64 @strlen(ptr %s)\n")
|
|
emith(" %sp = alloca i64\n")
|
|
emith(" %ep = alloca i64\n")
|
|
emith(" store i64 0, ptr %sp\n")
|
|
emith(" store i64 %n, ptr %ep\n")
|
|
emith(" br label %lcond\n")
|
|
emith("lcond:\n")
|
|
emith(" %a0 = load i64, ptr %sp\n")
|
|
emith(" %e0 = load i64, ptr %ep\n")
|
|
emith(" %lt0 = icmp ult i64 %a0, %e0\n")
|
|
emith(" br i1 %lt0, label %lchk, label %rcond\n")
|
|
emith("lchk:\n")
|
|
emith(" %p0 = getelementptr i8, ptr %s, i64 %a0\n")
|
|
emith(" %c0 = load i8, ptr %p0\n")
|
|
emith(" %ws0 = call i1 @lp_is_ws(i8 %c0)\n")
|
|
emith(" br i1 %ws0, label %linc, label %rcond\n")
|
|
emith("linc:\n")
|
|
emith(" %a1 = add i64 %a0, 1\n")
|
|
emith(" store i64 %a1, ptr %sp\n")
|
|
emith(" br label %lcond\n")
|
|
emith("rcond:\n")
|
|
emith(" %a2 = load i64, ptr %sp\n")
|
|
emith(" %e2 = load i64, ptr %ep\n")
|
|
emith(" %lt2 = icmp ult i64 %a2, %e2\n")
|
|
emith(" br i1 %lt2, label %rchk, label %build\n")
|
|
emith("rchk:\n")
|
|
emith(" %em1 = sub i64 %e2, 1\n")
|
|
emith(" %p1 = getelementptr i8, ptr %s, i64 %em1\n")
|
|
emith(" %c1 = load i8, ptr %p1\n")
|
|
emith(" %ws1 = call i1 @lp_is_ws(i8 %c1)\n")
|
|
emith(" br i1 %ws1, label %rdec, label %build\n")
|
|
emith("rdec:\n")
|
|
emith(" store i64 %em1, ptr %ep\n")
|
|
emith(" br label %rcond\n")
|
|
emith("build:\n")
|
|
emith(" %st = load i64, ptr %sp\n")
|
|
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 @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")
|
|
emith(" store i8 0, ptr %tp\n")
|
|
emith(" ret ptr %out\n")
|
|
emith("}\n")
|
|
emith("define i1 @lp_is_ws(i8 %c) {\n")
|
|
emith(" %a = icmp eq i8 %c, 32\n")
|
|
emith(" %b = icmp eq i8 %c, 9\n")
|
|
emith(" %d = icmp eq i8 %c, 10\n")
|
|
emith(" %e = icmp eq i8 %c, 13\n")
|
|
emith(" %ab = or i1 %a, %b\n")
|
|
emith(" %de = or i1 %d, %e\n")
|
|
emith(" %r = or i1 %ab, %de\n")
|
|
emith(" ret i1 %r\n")
|
|
emith("}\n")
|
|
emith("define ptr @lp_str_repeat(ptr %s, i32 %n32) {\n")
|
|
emith("entry:\n")
|
|
emith(" %nneg = icmp slt i32 %n32, 0\n")
|
|
emith(" %nn = select i1 %nneg, i32 0, i32 %n32\n")
|
|
emith(" %n = zext i32 %nn to i64\n")
|
|
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 @lp_malloc(i64 %sz)\n")
|
|
emith(" %ip = alloca i64\n")
|
|
emith(" store i64 0, ptr %ip\n")
|
|
emith(" br label %cond\n")
|
|
emith("cond:\n")
|
|
emith(" %i = load i64, ptr %ip\n")
|
|
emith(" %d = icmp ult i64 %i, %n\n")
|
|
emith(" br i1 %d, label %body, label %fin\n")
|
|
emith("body:\n")
|
|
emith(" %off = mul i64 %i, %L\n")
|
|
emith(" %dst = getelementptr i8, ptr %out, i64 %off\n")
|
|
emith(" call ptr @memcpy(ptr %dst, ptr %s, i64 %L)\n")
|
|
emith(" %i1 = add i64 %i, 1\n")
|
|
emith(" store i64 %i1, ptr %ip\n")
|
|
emith(" br label %cond\n")
|
|
emith("fin:\n")
|
|
emith(" %tp = getelementptr i8, ptr %out, i64 %tot\n")
|
|
emith(" store i8 0, ptr %tp\n")
|
|
emith(" ret ptr %out\n")
|
|
emith("}\n")
|
|
emith("define ptr @lp_str_pad(ptr %s, i32 %w32, i1 %left) {\n")
|
|
emith("entry:\n")
|
|
emith(" %L = call i64 @strlen(ptr %s)\n")
|
|
emith(" %w0 = sext i32 %w32 to i64\n")
|
|
emith(" %need = icmp ugt i64 %w0, %L\n")
|
|
emith(" br i1 %need, label %do, label %copy\n")
|
|
emith("copy:\n")
|
|
emith(" %sz0 = add i64 %L, 1\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")
|
|
emith(" store i8 0, ptr %t0\n")
|
|
emith(" ret ptr %o0\n")
|
|
emith("do:\n")
|
|
emith(" %pad = sub i64 %w0, %L\n")
|
|
emith(" %sz = add i64 %w0, 1\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")
|
|
emith(" %dstL = getelementptr i8, ptr %out, i64 %pad\n")
|
|
emith(" call ptr @memcpy(ptr %dstL, ptr %s, i64 %L)\n")
|
|
emith(" br label %term\n")
|
|
emith("padright:\n")
|
|
emith(" call ptr @memcpy(ptr %out, ptr %s, i64 %L)\n")
|
|
emith(" call void @lp_fill_sp(ptr %out, i64 %L, i64 %pad)\n")
|
|
emith(" br label %term\n")
|
|
emith("term:\n")
|
|
emith(" %tp = getelementptr i8, ptr %out, i64 %w0\n")
|
|
emith(" store i8 0, ptr %tp\n")
|
|
emith(" ret ptr %out\n")
|
|
emith("}\n")
|
|
emith("define void @lp_fill_sp(ptr %buf, i64 %start, i64 %count) {\n")
|
|
emith("entry:\n")
|
|
emith(" %ip = alloca i64\n")
|
|
emith(" store i64 0, ptr %ip\n")
|
|
emith(" br label %cond\n")
|
|
emith("cond:\n")
|
|
emith(" %i = load i64, ptr %ip\n")
|
|
emith(" %d = icmp ult i64 %i, %count\n")
|
|
emith(" br i1 %d, label %body, label %done\n")
|
|
emith("body:\n")
|
|
emith(" %off = add i64 %start, %i\n")
|
|
emith(" %p = getelementptr i8, ptr %buf, i64 %off\n")
|
|
emith(" store i8 32, ptr %p\n")
|
|
emith(" %i1 = add i64 %i, 1\n")
|
|
emith(" store i64 %i1, ptr %ip\n")
|
|
emith(" br label %cond\n")
|
|
emith("done:\n")
|
|
emith(" ret void\n")
|
|
emith("}\n")
|
|
}
|
|
|
|
# emit_text2_prelude — the allocating Text ops that build strings/slices:
|
|
# replace, join (over a []string), split (returns a []string). Emitted once per
|
|
# program that uses them (g_uses_textrt2). Slices are the {data,len,cap}
|
|
# %LSlice with str (ptr) elements.
|
|
function emit_text2_prelude() -> void {
|
|
emith("define ptr @lp_str_replace(ptr %s, ptr %from, ptr %to) {\n")
|
|
emith("entry:\n")
|
|
emith(" %lf = call i64 @strlen(ptr %from)\n")
|
|
emith(" %lz = icmp eq i64 %lf, 0\n")
|
|
emith(" br i1 %lz, label %copyall, label %scan\n")
|
|
emith("copyall:\n")
|
|
emith(" %ls0 = call i64 @strlen(ptr %s)\n")
|
|
emith(" %sz0 = add i64 %ls0, 1\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")
|
|
emith(" %lt = call i64 @strlen(ptr %to)\n")
|
|
emith(" %ls = call i64 @strlen(ptr %s)\n")
|
|
emith(" %cntp = alloca i64\n")
|
|
emith(" store i64 0, ptr %cntp\n")
|
|
emith(" %curp = alloca ptr\n")
|
|
emith(" store ptr %s, ptr %curp\n")
|
|
emith(" br label %ccond\n")
|
|
emith("ccond:\n")
|
|
emith(" %cur = load ptr, ptr %curp\n")
|
|
emith(" %hit = call ptr @strstr(ptr %cur, ptr %from)\n")
|
|
emith(" %isnull = icmp eq ptr %hit, null\n")
|
|
emith(" br i1 %isnull, label %csize, label %cinc\n")
|
|
emith("cinc:\n")
|
|
emith(" %c0 = load i64, ptr %cntp\n")
|
|
emith(" %c1 = add i64 %c0, 1\n")
|
|
emith(" store i64 %c1, ptr %cntp\n")
|
|
emith(" %adv = getelementptr i8, ptr %hit, i64 %lf\n")
|
|
emith(" store ptr %adv, ptr %curp\n")
|
|
emith(" br label %ccond\n")
|
|
emith("csize:\n")
|
|
emith(" %cnt = load i64, ptr %cntp\n")
|
|
emith(" %delta = sub i64 %lt, %lf\n")
|
|
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 @lp_malloc(i64 %osz)\n")
|
|
emith(" %srcp = alloca ptr\n")
|
|
emith(" store ptr %s, ptr %srcp\n")
|
|
emith(" %dstp = alloca ptr\n")
|
|
emith(" store ptr %out, ptr %dstp\n")
|
|
emith(" br label %bcond\n")
|
|
emith("bcond:\n")
|
|
emith(" %src = load ptr, ptr %srcp\n")
|
|
emith(" %h2 = call ptr @strstr(ptr %src, ptr %from)\n")
|
|
emith(" %n2 = icmp eq ptr %h2, null\n")
|
|
emith(" br i1 %n2, label %tail, label %seg\n")
|
|
emith("seg:\n")
|
|
emith(" %si = ptrtoint ptr %src to i64\n")
|
|
emith(" %hi = ptrtoint ptr %h2 to i64\n")
|
|
emith(" %seglen = sub i64 %hi, %si\n")
|
|
emith(" %dst0 = load ptr, ptr %dstp\n")
|
|
emith(" call ptr @memcpy(ptr %dst0, ptr %src, i64 %seglen)\n")
|
|
emith(" %dst1 = getelementptr i8, ptr %dst0, i64 %seglen\n")
|
|
emith(" call ptr @memcpy(ptr %dst1, ptr %to, i64 %lt)\n")
|
|
emith(" %dst2 = getelementptr i8, ptr %dst1, i64 %lt\n")
|
|
emith(" store ptr %dst2, ptr %dstp\n")
|
|
emith(" %src2 = getelementptr i8, ptr %h2, i64 %lf\n")
|
|
emith(" store ptr %src2, ptr %srcp\n")
|
|
emith(" br label %bcond\n")
|
|
emith("tail:\n")
|
|
emith(" %src3 = load ptr, ptr %srcp\n")
|
|
emith(" %rem = call i64 @strlen(ptr %src3)\n")
|
|
emith(" %dst3 = load ptr, ptr %dstp\n")
|
|
emith(" %remp1 = add i64 %rem, 1\n")
|
|
emith(" call ptr @memcpy(ptr %dst3, ptr %src3, i64 %remp1)\n")
|
|
emith(" ret ptr %out\n")
|
|
emith("}\n")
|
|
emith("define ptr @lp_str_join(ptr %h, ptr %sep) {\n")
|
|
emith("entry:\n")
|
|
emith(" %lp = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 1\n")
|
|
emith(" %len32 = load i32, ptr %lp\n")
|
|
emith(" %len = sext i32 %len32 to i64\n")
|
|
emith(" %dp = getelementptr inbounds %LSlice, ptr %h, i32 0, i32 0\n")
|
|
emith(" %data = load ptr, ptr %dp\n")
|
|
emith(" %lsep = call i64 @strlen(ptr %sep)\n")
|
|
emith(" %totp = alloca i64\n")
|
|
emith(" store i64 0, ptr %totp\n")
|
|
emith(" %ip = alloca i64\n")
|
|
emith(" store i64 0, ptr %ip\n")
|
|
emith(" br label %scond\n")
|
|
emith("scond:\n")
|
|
emith(" %i = load i64, ptr %ip\n")
|
|
emith(" %d = icmp ult i64 %i, %len\n")
|
|
emith(" br i1 %d, label %sbody, label %alloc\n")
|
|
emith("sbody:\n")
|
|
emith(" %ep = getelementptr ptr, ptr %data, i64 %i\n")
|
|
emith(" %es = load ptr, ptr %ep\n")
|
|
emith(" %el = call i64 @strlen(ptr %es)\n")
|
|
emith(" %t0 = load i64, ptr %totp\n")
|
|
emith(" %t1 = add i64 %t0, %el\n")
|
|
emith(" store i64 %t1, ptr %totp\n")
|
|
emith(" %i1 = add i64 %i, 1\n")
|
|
emith(" store i64 %i1, ptr %ip\n")
|
|
emith(" br label %scond\n")
|
|
emith("alloc:\n")
|
|
emith(" %nz = icmp ugt i64 %len, 0\n")
|
|
emith(" %lm1 = sub i64 %len, 1\n")
|
|
emith(" %seps = mul i64 %lm1, %lsep\n")
|
|
emith(" %sepsz = select i1 %nz, i64 %seps, i64 0\n")
|
|
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 @lp_malloc(i64 %osz)\n")
|
|
emith(" %dstp = alloca ptr\n")
|
|
emith(" store ptr %out, ptr %dstp\n")
|
|
emith(" %jp = alloca i64\n")
|
|
emith(" store i64 0, ptr %jp\n")
|
|
emith(" br label %jcond\n")
|
|
emith("jcond:\n")
|
|
emith(" %j = load i64, ptr %jp\n")
|
|
emith(" %d2 = icmp ult i64 %j, %len\n")
|
|
emith(" br i1 %d2, label %jbody, label %jfin\n")
|
|
emith("jbody:\n")
|
|
emith(" %jnz = icmp ugt i64 %j, 0\n")
|
|
emith(" br i1 %jnz, label %putsep, label %putel\n")
|
|
emith("putsep:\n")
|
|
emith(" %ds0 = load ptr, ptr %dstp\n")
|
|
emith(" call ptr @memcpy(ptr %ds0, ptr %sep, i64 %lsep)\n")
|
|
emith(" %ds1 = getelementptr i8, ptr %ds0, i64 %lsep\n")
|
|
emith(" store ptr %ds1, ptr %dstp\n")
|
|
emith(" br label %putel\n")
|
|
emith("putel:\n")
|
|
emith(" %ep2 = getelementptr ptr, ptr %data, i64 %j\n")
|
|
emith(" %es2 = load ptr, ptr %ep2\n")
|
|
emith(" %el2 = call i64 @strlen(ptr %es2)\n")
|
|
emith(" %ds2 = load ptr, ptr %dstp\n")
|
|
emith(" call ptr @memcpy(ptr %ds2, ptr %es2, i64 %el2)\n")
|
|
emith(" %ds3 = getelementptr i8, ptr %ds2, i64 %el2\n")
|
|
emith(" store ptr %ds3, ptr %dstp\n")
|
|
emith(" %j1 = add i64 %j, 1\n")
|
|
emith(" store i64 %j1, ptr %jp\n")
|
|
emith(" br label %jcond\n")
|
|
emith("jfin:\n")
|
|
emith(" %dsf = load ptr, ptr %dstp\n")
|
|
emith(" store i8 0, ptr %dsf\n")
|
|
emith(" ret ptr %out\n")
|
|
emith("}\n")
|
|
emith("define ptr @lp_str_split(ptr %s, ptr %sep) {\n")
|
|
emith("entry:\n")
|
|
emith(" %lsep = call i64 @strlen(ptr %sep)\n")
|
|
emith(" %cntp = alloca i64\n")
|
|
emith(" store i64 1, ptr %cntp\n")
|
|
emith(" %curp = alloca ptr\n")
|
|
emith(" store ptr %s, ptr %curp\n")
|
|
emith(" br label %ccond\n")
|
|
emith("ccond:\n")
|
|
emith(" %cur = load ptr, ptr %curp\n")
|
|
emith(" %hit = call ptr @strstr(ptr %cur, ptr %sep)\n")
|
|
emith(" %isnull = icmp eq ptr %hit, null\n")
|
|
emith(" br i1 %isnull, label %mk, label %cinc\n")
|
|
emith("cinc:\n")
|
|
emith(" %c0 = load i64, ptr %cntp\n")
|
|
emith(" %c1 = add i64 %c0, 1\n")
|
|
emith(" store i64 %c1, ptr %cntp\n")
|
|
emith(" %adv = getelementptr i8, ptr %hit, i64 %lsep\n")
|
|
emith(" store ptr %adv, ptr %curp\n")
|
|
emith(" br label %ccond\n")
|
|
emith("mk:\n")
|
|
emith(" %cnt = load i64, ptr %cntp\n")
|
|
emith(" %hdr = call ptr @lp_malloc(i64 16)\n")
|
|
emith(" %arrsz = mul i64 %cnt, 8\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")
|
|
emith(" %d1 = getelementptr inbounds %LSlice, ptr %hdr, i32 0, i32 1\n")
|
|
emith(" store i32 %cnt32, ptr %d1\n")
|
|
emith(" %d2 = getelementptr inbounds %LSlice, ptr %hdr, i32 0, i32 2\n")
|
|
emith(" store i32 %cnt32, ptr %d2\n")
|
|
emith(" %srcp = alloca ptr\n")
|
|
emith(" store ptr %s, ptr %srcp\n")
|
|
emith(" %ip = alloca i64\n")
|
|
emith(" store i64 0, ptr %ip\n")
|
|
emith(" br label %fcond\n")
|
|
emith("fcond:\n")
|
|
emith(" %i = load i64, ptr %ip\n")
|
|
emith(" %lt = icmp ult i64 %i, %cnt\n")
|
|
emith(" br i1 %lt, label %fbody, label %done\n")
|
|
emith("fbody:\n")
|
|
emith(" %src = load ptr, ptr %srcp\n")
|
|
emith(" %h2 = call ptr @strstr(ptr %src, ptr %sep)\n")
|
|
emith(" %n2 = icmp eq ptr %h2, null\n")
|
|
emith(" br i1 %n2, label %last, label %mid\n")
|
|
emith("mid:\n")
|
|
emith(" %si = ptrtoint ptr %src to i64\n")
|
|
emith(" %hi = ptrtoint ptr %h2 to i64\n")
|
|
emith(" %seglen = sub i64 %hi, %si\n")
|
|
emith(" br label %store\n")
|
|
emith("last:\n")
|
|
emith(" %rem = call i64 @strlen(ptr %src)\n")
|
|
emith(" br label %store\n")
|
|
emith("store:\n")
|
|
emith(" %seg = phi i64 [ %seglen, %mid ], [ %rem, %last ]\n")
|
|
emith(" %ssz = add i64 %seg, 1\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")
|
|
emith(" store i8 0, ptr %tp\n")
|
|
emith(" %slot = getelementptr ptr, ptr %arr, i64 %i\n")
|
|
emith(" store ptr %sub, ptr %slot\n")
|
|
emith(" %adv2 = getelementptr i8, ptr %h2, i64 %lsep\n")
|
|
emith(" store ptr %adv2, ptr %srcp\n")
|
|
emith(" %i1 = add i64 %i, 1\n")
|
|
emith(" store i64 %i1, ptr %ip\n")
|
|
emith(" br label %fcond\n")
|
|
emith("done:\n")
|
|
emith(" ret ptr %hdr\n")
|
|
emith("}\n")
|
|
}
|