Fil-C on Nix

Filnix wiki

mbrock/filnix/nanofil

escape.pl

Escape classification of allocs: alloc_classes/2 tells, for each alloc of a function, whether its address is only used for loads and stores at known offsets. Prior art: QBE's ALoc/AEsc.

The module also exports the relations alloc_classes/2 is built from: address_temps/2, load_width/2 and def_counts/2.

The analysis rests on one fact: a local alloc can only be reached through its own address, so no other pointer or integer can name it.

Offsets are exact integers. An IR add wraps modulo 2^64, but here a huge constant gives a huge offset, which promote's bounds check refuses.

useslists
usesassoc
usespairs
usesirop_kind/2
load_width?LoadType, ?Widthnondet

A supported integer or pointer load reads a slot of width Width (b h w l p). Other load types must make the allocation escape.

load_width
28ll
29sww
30uww
31shh
32uhh
33sbb
34ubb
35pp
alloc_classes+Func, -Classesdet

Classes is [A-Class] for every alloc temp A of Func, in order, with Class one of:

- local(Size, Accesses): every use of A's address is the address of
  a load or store at a fixed offset, possibly through add/sub of
  constants or copy. Accesses is an ordset of acc(Off, Width),
  Width in b h w l p. Size is the alloc's operand.
- escapes(Why): the address is used any other way (stored, passed,
  returned, compared, converted, merged in a phi, offset by a
  variable, loaded with an unsupported type), or it or a temp
  derived from it is defined more than once, so offsets are unknown.
51alloc_classesF, Classes ←
F = func_, _, _, _, Blocks
findallI,
memberblock_, _, Is, _, Blocks
memberI, Is
,
Insts
def_countsF, DefCounts
findallA−Size, memberlettmpA, _, alloc_, Size, Insts, Allocs
findallRoot−E,
memberI, Insts
inst_eventI, Addrs, Root−E
,
InstEvents
findallRoot−escphi,
memberblock_, Phis, _, _, Blocks
memberphi_, _, Args, Phis
member_−tmpX, Args
get_assocX, Addrs, Root−_
,
PhiEscapes
findallRoot−escjump,
memberblock_, _, _, Jump, Blocks
jump_valueJump, tmpX
get_assocX, Addrs, Root−_
,
JumpEscapes
A temp derived from A that is also defined some other way.
findallRoot−escredefined,
gen_assocX, Addrs, Root−_
get_assocX, DefCounts, N
N > 1
,
Redefined
appendInstEvents, PhiEscapes, JumpEscapes, Redefined, Events0
Group once by allocation, preserving event order (and hence the
first escape reason), rather than scanning every event per alloc.
keysortEvents0, Sorted
group_pairs_by_keySorted, Pairs
list_to_assocPairs, Events
maplistevents_alloc_classEvents, Allocs, Classes
events_alloc_class+Events, +A−Size, −A−Class

Class is the class of the alloc A, of operand Size, given the assoc Events of each alloc's events in order: escapes for the first escape, or else local.

88events_alloc_classEvents, A−Size, A−Class ←
get_assocA, Events, Es
→
true
else
Es = []
memberchkescWhy, Es
→
Class = escapesWhy
else
findallAcc, memberaccAcc, Es, Accs0
sortAccs0, Accs
Class = localSize, Accs
inst_event+Ins, +Addrs, −Root−Eventnondet

Event is what Ins does with the address of alloc Root: an access at a known offset, or an escape of every alloc whose address it reads. A constant offset (a derived address, seen by address_temps) is neither.

101inst_eventletD, K, Op, Args, Addrs, Event ←
op_kindOp, Kind
kind_eventKind, letD, K, Op, Args, Addrs, Event
104inst_eventstoreW, V, A, Addrs, Event ←
V = tmpX
get_assocX, Addrs, Root−_
Event = Root−escstored
or
A = tmpX
get_assocX, Addrs, Root−Off
Event = Root−accaccOff, W
112inst_eventcall_, F, Args, Addrs, Root−esccall ←
findallV, memberarg_, V, Args, Vs
membertmpX, F|Vs
get_assocX, Addrs, Root−_
kind_event+Kind, +Ins, +Addrs, −Root−Eventnondet

as inst_event/3, for the instruction Ins of an Op of Kind. A load accesses its address only when its slot width is supported; otherwise it escapes, so promotion cannot mistake an unknown access for no use. Every other op lets the addresses it reads escape.

122kind_eventload, let_, _, loadT, tmpX, Addrs, Root−Event ←
get_assocX, Addrs, Root−Off
→
Event = accaccOff, W
else
Event = escloadT
129kind_eventadditive, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
130kind_eventalu, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
131kind_eventshift, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
132kind_eventneg, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
133kind_eventcopy, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
134kind_eventptoi, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
135kind_eventitop, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
136kind_eventva_args, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
137kind_eventva_arg, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
138kind_eventsetjmp, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
139kind_eventva_arg, let_, _, _, tmpX, Addrs, Root−accaccOff, p ←
get_assocX, Addrs, Root−Off
141kind_eventcmp, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
142kind_eventext, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
143kind_eventalloc, Ins, Addrs, Event ←
ins_escapeIns, Addrs, Event
ins_escape+Ins, +Addrs, −Root−escOpnondet

Ins, an instruction of Op that is not a derived address, reads the address of alloc Root.

147ins_escapeletD, K, Op, Args, Addrs, Root−escOp ←
¬
offset_ofletD, K, Op, Args, Y, _derived address
get_assocY, Addrs, _
membertmpX, Args
get_assocX, Addrs, Root−_
153jump_valuebranchV, _, _, V
154jump_valueretV, V
155jump_valueretsVs, V ←
memberV, Vs
offset_of+Ins, -Src, -Delta

Ins computes Src + Delta.

158offset_oflet_, _, add, tmpX, constN, X, N
159offset_oflet_, _, add, constN, tmpX, X, N
160offset_oflet_, _, sub, tmpX, constN, X, D ←
D is −N
161offset_oflet_, _, copy, tmpX, X, 0
address_temps+Func, -Addrsdet

Addrs is the assoc Temp -> A-Off for each alloc temp A (Off 0) and each temp derived from one by constant offsets, whatever the class.

168address_tempsfunc_, _, _, _, Blocks, Addrs ←
findallI,
memberblock_, _, Is, _, Blocks
memberI, Is
,
Insts
findallA−A−0, memberlettmpA, _, alloc_, _, Insts, AllocPairs
list_to_assocAllocPairs, Addrs0
edge(Pos, D, N): instruction Pos defines D as the source plus N.
findallX−edgePos, D, N,
nth0Pos, Insts, Ins
Ins = lettmpD, _, _, _
offset_ofIns, X, N
,
Edges0
keysortEdges0, Edges1
group_pairs_by_keyEdges1, Edges
list_to_assocEdges, BySource
assoc_to_listAddrs0, Seeds
layers_addrsSeeds, BySource, Addrs0, Addrs
layers_addrs+Layer, +BySource, +Addrs0, -Addrs

Addrs is Addrs0 with the temps derived, directly or not, from the X-(Root-Off) pairs of Layer and not yet in Addrs0. A dependency is followed only when its source is first resolved, a whole layer at a time: as in the old fixed point, a redefined temp takes its earliest-resolved definition, then instruction order breaks ties. Cycles without an allocation seed remain unresolved.

191layers_addrs[], _, Addrs, Addrs
192layers_addrsS|Ss, BySource, Addrs0, Addrs ←
findallPos−D−Root−Off,
memberX−Root−Off0, S|Ss
get_assocX, BySource, Edges
memberedgePos, D, N, Edges
¬get_assocD, Addrs0, _
Off is Off0 + N
,
Found
keysortFound, Ordered
pairs_valuesOrdered, Pairs
One entry per temp; redefinitions are caught later.
sort1, @<, Pairs, New
foldlpair_assoc, New, Addrs0, Addrs1
layers_addrsNew, BySource, Addrs1, Addrs
207pair_assocK−V, Assoc0, Assoc ←
put_assocK, Assoc0, V, Assoc
def_counts+Func, -Countsdet

Counts is the assoc Temp -> number of definitions of Temp in Func (parameters, phis, instructions and call results).

214def_countsfunc_, _, _, Params, Blocks, Counts ←
findallN, memberparam_, tmpN, Params, ParamDefs
findallN,
memberblock_, Phis, Insts, _, Blocks
memberphitmpN, _, _, Phis
or
memberlettmpN, _, _, _, Insts
or
membercallresulttmpN, _, _, _, Insts
or
membercalltupleRs, _, _, Insts
memberresulttmpN, _, Rs
,
BlockDefs
appendParamDefs, BlockDefs, Defs
msortDefs, Sorted
clumped_pairsSorted, Pairs
list_to_assocPairs, Counts
clumped_pairs+Sorted, -Pairs

Pairs is X-N for each run of N equal elements X of Sorted.

232clumped_pairs[], []
233clumped_pairsX|Xs, X−N|Ps ←
run_ofX, Xs, 1, N, Rest
run_of+X, +Xs, +N0, -N, -Rest

Xs is a run of N - N0 copies of X followed by Rest, which does not start with X.

239run_ofX, Y|Ys, N0, N, Rest ←
X ≡ Y
!
N1 is N0 + 1
run_ofX, Ys, N1, N, Rest
244run_of_, Rest, N, N, Rest