compiler: free a string an expression made once it has been used

The left half of a + chain, a template's pieces and holes, a number's text and a side made only to be
compared are marked fresh and freed after the +, ==, != or print that reads them. lp_int_str and
lp_long_str move their digits to the start of the buffer, so the pointer they return is the one
malloc gave. Reseeded. examples/lang/string_temps.ludic: kept intermediates stay good, and 20,000
rounds grow the heap 0 bytes (2.9 MB before).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 12:06:45 +03:00
parent 2fe4018d28
commit 9660587e10
10 changed files with 56019 additions and 48735 deletions

View file

@ -133,9 +133,17 @@ function to_long(v: Val) -> pointer {
function emit_str_op(op: pointer, a: Val, b: Val) -> Val {
g_uses_str = true
if (op == ("+")) {
return val(emit_bind(`call ptr @lp_str_concat(ptr {a.code}, ptr {b.code})`), "string")
let r = fresh_val(emit_bind(`call ptr @lp_str_concat(ptr {a.code}, ptr {b.code})`), "string")
# a half this expression made is copied now and held by nothing: `a + "/" + b` and every
# template's pieces once left one string behind per `+`
if a.fresh { emit(` call void @free(ptr {a.code})\n`) }
if b.fresh and b.code != a.code { emit(` call void @free(ptr {b.code})\n`) }
return r
}
let r = emit_bind(`call i32 @lp_str_eq(ptr {a.code}, ptr {b.code})`)
# a side made just to be compared is held by nothing once it has been: `` `{x}` == "..." ``
if a.fresh { emit(` call void @free(ptr {a.code})\n`) }
if b.fresh and b.code != a.code { emit(` call void @free(ptr {b.code})\n`) }
if (op == ("!=")) {
let c = emit_bind(`icmp eq i32 {r}, 0`)
return val(emit_bind(`zext i1 {c} to i32`), "bool")