Fil-C on Nix

Filnix wiki

mbrock/filnix/nanofil

frame_slots.pl

Conservative stack-slot allocation for the Fil-C backend: temp_slots/6 assigns each temporary a frame slot, and temporaries whose live intervals are disjoint may share one.

A temporary's interval is closed and covers every write (even of a dead result), every use by an instruction and every block boundary where it is live in or out. One lowered instruction, including all its helper calls, is thus indivisible. Two temporaries share a slot only when their intervals are strictly disjoint, so a result never overwrites its operands.

PoolHolds
pointerp temporaries: each slot is a payload slot and its lower, allocated together
scalarw, l, s and d temporaries; they never use the pointer pool

A variadic function's hidden va_snapshot parameter is kept live for the whole invocation. Functions that call setjmp must not use this allocator (docs/setjmp.md).

moduleframe_slots
useslists
usesassoc
usespairs
usescfg
temp_slots+Params, +Blocks, +Temps, -Aliases, -ScalarCount, -PtrCount

Aliases maps each temp name to physical storage(Pool, Index).

29temp_slotsParams, Blocks, Temps, Aliases, NS, NP ←
temp_livenessBlocks, In, Out
foldlparam_point, Params, [], R1
block_rangesBlocks, In, Out, 1, End, R1, R2
va_args reads this backend-only parameter implicitly. Reserve both
its address and lower for the entire invocation.
memberchkparamp, tmphiddenva_snapshot, Params
→
touchhiddenva_snapshot, End, R2, Points
else
Points = R2
Batch the points rather than updating a persistent tree for every
use. Trealla otherwise retains gigabytes of intermediate trees on
large functions. Grouping computes exactly the same convex hulls.
keysortPoints, Sorted
group_pairs_by_keySorted, Groups
maplistgroup_range, Groups, Pairs
list_to_assocPairs, Ranges
maplisttemp_intervalRanges, Temps, Intervals0
sortIntervals0, Intervals
empty_assocA0
allocateIntervals, [], [], 0, NS, 0, NP, A0, Aliases
49param_pointparam_, tmpN, R0, R ←
touchN, 0, R0, R
51touchN, P, R, N−P|R
53group_rangeN−Ps, N−Lo−Hi ←
min_listPs, Lo
max_listPs, Hi
55points[], _, R, R
56pointsN|Ns, P, R0, R ←
touchN, P, R0, R1
pointsNs, P, R1, R
59block_ranges[], _, _, P, P, R, R
60block_rangesblockL, Phis, Insts, Jump|Bs, In, Out, P, End, R0, R ←
get_assocL, In, LiveIn
pointsLiveIn, P, R0, R1
phi_pointsPhis, P, R1, R2
P1 is P + 1
inst_rangesInsts, P1, Exit, R2, R3
jump_usesJump, Uses
pointsUses, Exit, R3, R4
get_assocL, Out, LiveOut
pointsLiveOut, Exit, R4, R5
Next is Exit + 1
block_rangesBs, In, Out, Next, End, R5, R
70phi_points[], _, R, R
71phi_pointsphitmpN, _, _|Ps, P, R0, R ←
touchN, P, R0, R1
phi_pointsPs, P, R1, R
74inst_ranges[], P, P, R, R
75inst_rangesI|Is, P, End, R0, R ←
inst_usesI, Uses
pointsUses, P, R0, R1
findallN, inst_defI, N, Defs
pointsDefs, P, R1, R2
Next is P + 1
inst_rangesIs, Next, End, R2, R
81temp_intervalRanges, N−K, rangeStart, End, Pool, N ←
get_assocN, Ranges, Start−End
class_poolK, Pool
class_pool
85ppointer
86wscalar
87lscalar
88sscalar
89dscalar
91allocate[], _, _, NS, NS, NP, NP, A, A
92allocaterangeStart, End, Pool, N|Rs, SS0, PS0, NS0, NS, NP0, NP, A0, A ←
pool_slotPool, Start, End, SS0, SS, PS0, PS, NS0, NS1, NP0, NP1, I
put_assocN, A0, storagePool, I, A1
allocateRs, SS, PS, NS1, NS, NP1, NP, A1, A
97pool_slotscalar, S, E, SS0, SS, PS, PS, NS0, NS, NP, NP, I ←
reuse_slotSS0, S, E, NS0, NS, SS, I
99pool_slotpointer, S, E, SS, SS, PS0, PS, NS, NS, NP0, NP, I ←
reuse_slotPS0, S, E, NP0, NP, PS, I

One end point per physical slot, not an interference graph. Reuse only strictly disjoint intervals: results cannot overwrite their operands.

104reuse_slot[], _, E, N0, N, slotN0, E, N0 ←
N is N0 + 1
105reuse_slotslotI0, E0|Ss0, S, E, N0, N, Ss, I ←
E0 < S
→
Ss = slotI0, E|Ss0
I = I0
N = N0
else
Ss = slotI0, E0|Tail
reuse_slotSs0, S, E, N0, N, Tail, I