dealloc_freelist.ll.bak raw
1 ; Scope-based memory management runtime.
2 ; alloc uses calloc with 16-byte magic header.
3 ; free checks magic before freeing.
4 ; Scope tracking via linked list with save points.
5 ; sliceGrow does NOT free old buffers - scope system handles lifetime.
6
7 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
8 target triple = "x86_64-unknown-linux-musleabihf"
9
10 @runtime.zeroSizedAlloc = external hidden global i8
11
12 declare ptr @calloc(i64, i64)
13 declare void @free(ptr)
14 declare ptr @realloc(ptr, i64)
15
16 declare hidden void @runtime.runtimePanic(ptr, i64, i64, ptr)
17 @.str.oom = hidden constant [13 x i8] c"out of memory"
18
19 define hidden noalias nonnull ptr @runtime.alloc(i64 %size, ptr %layout, ptr %context) #0 {
20 entry:
21 %isz = icmp eq i64 %size, 0
22 br i1 %isz, label %zero, label %nonzero
23 zero:
24 ret ptr @runtime.zeroSizedAlloc
25 nonzero:
26 %aligned = add i64 %size, 15
27 %size16 = and i64 %aligned, -16
28 %total = add i64 %size16, 16
29 %base = call ptr @calloc(i64 1, i64 %total)
30 %ok = icmp ne ptr %base, null
31 br i1 %ok, label %done, label %oom
32 oom:
33 call void @runtime.runtimePanic(ptr @.str.oom, i64 13, i64 13, ptr undef)
34 unreachable
35 done:
36 store i64 -6872988504188559820, ptr %base, align 8
37 %user = getelementptr i8, ptr %base, i64 16
38 ret ptr %user
39 }
40
41 define hidden void @runtime.free(ptr %ptr, ptr %context) {
42 entry:
43 %isnil = icmp eq ptr %ptr, null
44 br i1 %isnil, label %done, label %check
45 check:
46 %base = getelementptr i8, ptr %ptr, i64 -16
47 %magic = load i64, ptr %base, align 8
48 %is_ours = icmp eq i64 %magic, -6872988504188559820
49 br i1 %is_ours, label %dofree, label %done
50 dofree:
51 store i64 0, ptr %base, align 8
52 call void @free(ptr %base)
53 br label %done
54 done:
55 ret void
56 }
57
58 define hidden ptr @runtime.realloc(ptr %ptr, i64 %size) {
59 entry:
60 %base = getelementptr i8, ptr %ptr, i64 -16
61 %aligned = add i64 %size, 15
62 %size16 = and i64 %aligned, -16
63 %total = add i64 %size16, 16
64 %p = call ptr @realloc(ptr %base, i64 %total)
65 %user = getelementptr i8, ptr %p, i64 16
66 ret ptr %user
67 }
68
69 define hidden void @runtime.hashmapDestroy(ptr %m, ptr %context) {
70 entry:
71 %isnil = icmp eq ptr %m, null
72 br i1 %isnil, label %done, label %destroy
73 destroy:
74 %bucketsPtr = load ptr, ptr %m, align 8
75 %hasBuckets = icmp ne ptr %bucketsPtr, null
76 br i1 %hasBuckets, label %freeBuckets, label %freeMap
77 freeBuckets:
78 %keySizePtr = getelementptr i8, ptr %m, i64 24
79 %keySize = load i64, ptr %keySizePtr, align 8
80 %valSizePtr = getelementptr i8, ptr %m, i64 32
81 %valSize = load i64, ptr %valSizePtr, align 8
82 %ks8 = mul i64 %keySize, 8
83 %vs8 = mul i64 %valSize, 8
84 %bs1 = add i64 16, %ks8
85 %bucketSize = add i64 %bs1, %vs8
86 %bitsPtr = getelementptr i8, ptr %m, i64 40
87 %bits8 = load i8, ptr %bitsPtr, align 1
88 %bits = zext i8 %bits8 to i64
89 %numBuckets = shl i64 1, %bits
90 br label %bucketLoop
91 bucketLoop:
92 %i = phi i64 [ 0, %freeBuckets ], [ %inext, %bucketDone ]
93 %idone = icmp uge i64 %i, %numBuckets
94 br i1 %idone, label %freeBucketArray, label %processBucket
95 processBucket:
96 %off = mul i64 %bucketSize, %i
97 %bucket = getelementptr i8, ptr %bucketsPtr, i64 %off
98 %overflowPtr = getelementptr i8, ptr %bucket, i64 8
99 %overflow = load ptr, ptr %overflowPtr, align 8
100 br label %overflowLoop
101 overflowLoop:
102 %ov = phi ptr [ %overflow, %processBucket ], [ %ovNext, %freeOverflow ]
103 %ovDone = icmp eq ptr %ov, null
104 br i1 %ovDone, label %bucketDone, label %freeOverflow
105 freeOverflow:
106 %ovNextPtr = getelementptr i8, ptr %ov, i64 8
107 %ovNext = load ptr, ptr %ovNextPtr, align 8
108 call void @runtime.free(ptr %ov, ptr undef)
109 br label %overflowLoop
110 bucketDone:
111 %inext = add i64 %i, 1
112 br label %bucketLoop
113 freeBucketArray:
114 call void @runtime.free(ptr %bucketsPtr, ptr undef)
115 br label %freeMap
116 freeMap:
117 call void @runtime.free(ptr %m, ptr undef)
118 br label %done
119 done:
120 ret void
121 }
122
123 declare hidden void @runtime.memmove(ptr, ptr, i64, ptr)
124 declare hidden void @runtime.negativeShiftPanic(ptr)
125 declare hidden i32 @"math/bits.Len"(i32, ptr)
126 declare hidden ptr @"(internal/gclayout.Layout).AsPtr"(i64, ptr)
127
128 define hidden { ptr, i64, i64 } @runtime.sliceGrow(ptr %oldBuf, i64 %oldLen, i64 %oldCap, i64 %newCap, i64 %elemSize, ptr %context) #1 {
129 entry:
130 %fits = icmp uge i64 %oldCap, %newCap
131 br i1 %fits, label %no_grow, label %grow
132 no_grow:
133 %r0 = insertvalue { ptr, i64, i64 } zeroinitializer, ptr %oldBuf, 0
134 %r1 = insertvalue { ptr, i64, i64 } %r0, i64 %oldLen, 1
135 %r2 = insertvalue { ptr, i64, i64 } %r1, i64 %oldCap, 2
136 ret { ptr, i64, i64 } %r2
137 grow:
138 %tr = trunc i64 %newCap to i32
139 %bits = call i32 @"math/bits.Len"(i32 %tr, ptr undef)
140 %neg = icmp slt i32 %bits, 0
141 br i1 %neg, label %shift_throw, label %shift_ok
142 shift_ok:
143 %overflow = icmp uge i32 %bits, 64
144 %ext = zext i32 %bits to i64
145 %shifted = shl i64 1, %ext
146 %roundCap = select i1 %overflow, i64 0, i64 %shifted
147 %small = icmp ult i64 %elemSize, 8
148 br i1 %small, label %set_layout, label %do_alloc
149 set_layout:
150 %lay = call ptr @"(internal/gclayout.Layout).AsPtr"(i64 3, ptr undef)
151 br label %do_alloc
152 do_alloc:
153 %layout = phi ptr [ null, %shift_ok ], [ %lay, %set_layout ]
154 %totalSz = mul i64 %roundCap, %elemSize
155 %buf = call ptr @runtime.alloc(i64 %totalSz, ptr %layout, ptr undef)
156 %hasData = icmp ugt i64 %oldLen, 0
157 br i1 %hasData, label %copy, label %ret
158 copy:
159 %copySz = mul i64 %oldLen, %elemSize
160 call void @runtime.memmove(ptr %buf, ptr %oldBuf, i64 %copySz, ptr undef)
161 br label %ret
162 ret:
163 %s0 = insertvalue { ptr, i64, i64 } zeroinitializer, ptr %buf, 0
164 %s1 = insertvalue { ptr, i64, i64 } %s0, i64 %oldLen, 1
165 %s2 = insertvalue { ptr, i64, i64 } %s1, i64 %roundCap, 2
166 ret { ptr, i64, i64 } %s2
167 shift_throw:
168 call void @runtime.negativeShiftPanic(ptr undef)
169 unreachable
170 }
171
172 define void @runtime._panic(ptr %msg) {
173 call void @runtime.runtimePanic(ptr %msg, i64 0, i64 0, ptr null)
174 unreachable
175 }
176
177 define void @runtime._panicstr({ ptr, i64, i64 } %s) {
178 %p = extractvalue { ptr, i64, i64 } %s, 0
179 %l = extractvalue { ptr, i64, i64 } %s, 1
180 %c = extractvalue { ptr, i64, i64 } %s, 2
181 call void @runtime.runtimePanic(ptr %p, i64 %l, i64 %c, ptr null)
182 unreachable
183 }
184
185 define void @syscall.runtime_entersyscall() { ret void }
186 define void @syscall.runtime_exitsyscall() { ret void }
187
188 @environ = external global ptr
189 declare i64 @strlen(ptr)
190 declare i32 @setenv(ptr, ptr, i32)
191
192 define hidden { ptr, i64, i64 } @syscall.runtime_envs(ptr %context) {
193 entry:
194 %ep = load ptr, ptr @environ, align 8
195 %isnil = icmp eq ptr %ep, null
196 br i1 %isnil, label %empty, label %count
197 count:
198 br label %loop
199 loop:
200 %p = phi ptr [ %ep, %count ], [ %nextp, %next ]
201 %n = phi i64 [ 0, %count ], [ %n1, %next ]
202 %cur = load ptr, ptr %p, align 8
203 %done = icmp eq ptr %cur, null
204 br i1 %done, label %build, label %next
205 next:
206 %n1 = add i64 %n, 1
207 %nextp = getelementptr ptr, ptr %p, i64 1
208 br label %loop
209 build:
210 %sz = mul i64 %n, 24
211 %buf = call ptr @runtime.alloc(i64 %sz, ptr null, ptr null)
212 br label %fill
213 fill:
214 %i = phi i64 [ 0, %build ], [ %i1, %fillnext ]
215 %idone = icmp uge i64 %i, %n
216 br i1 %idone, label %retlbl, label %fillbody
217 fillbody:
218 %envp = getelementptr ptr, ptr %ep, i64 %i
219 %str = load ptr, ptr %envp, align 8
220 %slen = call i64 @strlen(ptr %str)
221 %slot = getelementptr { ptr, i64, i64 }, ptr %buf, i64 %i
222 store ptr %str, ptr %slot, align 8
223 %lenp = getelementptr i8, ptr %slot, i64 8
224 store i64 %slen, ptr %lenp, align 8
225 %capp = getelementptr i8, ptr %slot, i64 16
226 store i64 %slen, ptr %capp, align 8
227 br label %fillnext
228 fillnext:
229 %i1 = add i64 %i, 1
230 br label %fill
231 retlbl:
232 %r0 = insertvalue { ptr, i64, i64 } zeroinitializer, ptr %buf, 0
233 %r1 = insertvalue { ptr, i64, i64 } %r0, i64 %n, 1
234 %r2 = insertvalue { ptr, i64, i64 } %r1, i64 %n, 2
235 ret { ptr, i64, i64 } %r2
236 empty:
237 ret { ptr, i64, i64 } zeroinitializer
238 }
239
240 define void @syscall.runtimeSetenv({ ptr, i64, i64 } %k, { ptr, i64, i64 } %v, ptr %context) {
241 %kptr = extractvalue { ptr, i64, i64 } %k, 0
242 %vptr = extractvalue { ptr, i64, i64 } %v, 0
243 %1 = call i32 @setenv(ptr %kptr, ptr %vptr, i32 1)
244 ret void
245 }
246
247 define { i64, i64, i64 } @"internal/runtime/syscall.Syscall6"(i64 %num, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6) {
248 %1 = call { i64, i64 } asm sideeffect "syscall", "={rax},={rdx},{rax},{rdi},{rsi},{rdx},{r10},{r8},{r9},~{rcx},~{r11},~{memory}"(i64 %num, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6)
249 %r1 = extractvalue { i64, i64 } %1, 0
250 %r2 = extractvalue { i64, i64 } %1, 1
251 %ret1 = insertvalue { i64, i64, i64 } undef, i64 %r1, 0
252 %ret2 = insertvalue { i64, i64, i64 } %ret1, i64 %r2, 1
253 %ret3 = insertvalue { i64, i64, i64 } %ret2, i64 0, 2
254 ret { i64, i64, i64 } %ret3
255 }
256
257 ; scopePush: push allocation onto scope list.
258 ; Node layout: {ptr payload, ptr next} (16 bytes)
259 define hidden void @runtime.scopePush(ptr %payload, ptr %headSlot) {
260 entry:
261 %isnil = icmp eq ptr %payload, null
262 br i1 %isnil, label %done, label %push
263 push:
264 %node = call ptr @calloc(i64 1, i64 16)
265 %ok = icmp ne ptr %node, null
266 br i1 %ok, label %fill, label %done
267 fill:
268 store ptr %payload, ptr %node, align 8
269 %nextSlot = getelementptr i8, ptr %node, i64 8
270 %oldHead = load ptr, ptr %headSlot, align 8
271 store ptr %oldHead, ptr %nextSlot, align 8
272 store ptr %node, ptr %headSlot, align 8
273 br label %done
274 done:
275 ret void
276 }
277
278 ; scopeFreeTo: walk from head, free each payload+node, stop at sentinel.
279 define hidden ptr @runtime.scopeFreeTo(ptr %head, ptr %sentinel) {
280 entry:
281 br label %loop
282 loop:
283 %cur = phi ptr [ %head, %entry ], [ %next, %freeself ]
284 %atEnd = icmp eq ptr %cur, %sentinel
285 br i1 %atEnd, label %ret, label %checknull
286 checknull:
287 %isnull = icmp eq ptr %cur, null
288 br i1 %isnull, label %ret, label %freenode
289 freenode:
290 %payload = load ptr, ptr %cur, align 8
291 %nextSlot = getelementptr i8, ptr %cur, i64 8
292 %next0 = load ptr, ptr %nextSlot, align 8
293 %paynil = icmp eq ptr %payload, null
294 br i1 %paynil, label %freeself, label %freepay
295 freepay:
296 call void @runtime.free(ptr %payload, ptr undef)
297 br label %freeself
298 freeself:
299 %next = phi ptr [ %next0, %freenode ], [ %next0, %freepay ]
300 call void @free(ptr %cur)
301 br label %loop
302 ret:
303 ret ptr %sentinel
304 }
305
306 ; scopeRelocate: move allocation from inner scope to outer scope.
307 define hidden void @runtime.scopeRelocate(ptr %payload, ptr %headSlot, ptr %saveSlot) {
308 entry:
309 %isnil = icmp eq ptr %payload, null
310 br i1 %isnil, label %done, label %start
311 start:
312 %saved = load ptr, ptr %saveSlot, align 8
313 %head = load ptr, ptr %headSlot, align 8
314 %headIsSave = icmp eq ptr %head, %saved
315 br i1 %headIsSave, label %done, label %headnullchk
316 headnullchk:
317 %headNull = icmp eq ptr %head, null
318 br i1 %headNull, label %done, label %checkhead
319 checkhead:
320 %headPay = load ptr, ptr %head, align 8
321 %headMatch = icmp eq ptr %headPay, %payload
322 br i1 %headMatch, label %unlinkhead, label %search
323 unlinkhead:
324 %headNext = getelementptr i8, ptr %head, i64 8
325 %hn = load ptr, ptr %headNext, align 8
326 store ptr %hn, ptr %headSlot, align 8
327 %savIsNull = icmp eq ptr %saved, null
328 br i1 %savIsNull, label %insertnull, label %insertafter
329 insertnull:
330 store ptr null, ptr %headNext, align 8
331 store ptr %head, ptr %saveSlot, align 8
332 br label %done
333 insertafter:
334 %savNext = getelementptr i8, ptr %saved, i64 8
335 %sn = load ptr, ptr %savNext, align 8
336 store ptr %sn, ptr %headNext, align 8
337 store ptr %head, ptr %savNext, align 8
338 br label %done
339 search:
340 br label %sloop
341 sloop:
342 %prev = phi ptr [ %head, %search ], [ %scur, %snext ]
343 %prevNextSlot = getelementptr i8, ptr %prev, i64 8
344 %scur = load ptr, ptr %prevNextSlot, align 8
345 %curDone = icmp eq ptr %scur, %saved
346 br i1 %curDone, label %done, label %schecknull
347 schecknull:
348 %curNull = icmp eq ptr %scur, null
349 br i1 %curNull, label %done, label %smatch
350 smatch:
351 %curPay = load ptr, ptr %scur, align 8
352 %curMatch = icmp eq ptr %curPay, %payload
353 br i1 %curMatch, label %unlinkmid, label %snext
354 snext:
355 br label %sloop
356 unlinkmid:
357 %curNextSlot = getelementptr i8, ptr %scur, i64 8
358 %cn = load ptr, ptr %curNextSlot, align 8
359 store ptr %cn, ptr %prevNextSlot, align 8
360 %savIsNull2 = icmp eq ptr %saved, null
361 br i1 %savIsNull2, label %insertnull2, label %insertafter2
362 insertnull2:
363 store ptr null, ptr %curNextSlot, align 8
364 store ptr %scur, ptr %saveSlot, align 8
365 br label %done
366 insertafter2:
367 %savNext2 = getelementptr i8, ptr %saved, i64 8
368 %sn2 = load ptr, ptr %savNext2, align 8
369 store ptr %sn2, ptr %curNextSlot, align 8
370 store ptr %scur, ptr %savNext2, align 8
371 br label %done
372 done:
373 ret void
374 }
375
376 ; scopeEscapeReturn: null out payload so scopeFreeTo won't free it.
377 define hidden void @runtime.scopeEscapeReturn(ptr %payload, ptr %headSlot) {
378 entry:
379 %isnil = icmp eq ptr %payload, null
380 br i1 %isnil, label %done, label %start
381 start:
382 %head = load ptr, ptr %headSlot, align 8
383 br label %loop
384 loop:
385 %cur = phi ptr [ %head, %start ], [ %next, %nomatch ]
386 %curnil = icmp eq ptr %cur, null
387 br i1 %curnil, label %done, label %check
388 check:
389 %curPay = load ptr, ptr %cur, align 8
390 %match = icmp eq ptr %curPay, %payload
391 br i1 %match, label %nullify, label %nomatch
392 nullify:
393 store ptr null, ptr %cur, align 8
394 br label %done
395 nomatch:
396 %nextSlot = getelementptr i8, ptr %cur, i64 8
397 %next = load ptr, ptr %nextSlot, align 8
398 br label %loop
399 done:
400 ret void
401 }
402
403 attributes #0 = { noinline nounwind allockind("alloc,zeroed") allocsize(0) uwtable(sync) "alloc-family"="runtime.alloc" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
404 attributes #1 = { noinline nounwind uwtable(sync) "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
405