Fil-C on Nix

Filnix wiki

mbrock/filnix/nanofil

filc_amd64.pl

The Fil-C backend for x86-64: filc_abi.pl lowers checked functions to frame, call and entry products; this module places their words and emits asm.pl lines whose GNU as text links with code clang builds for filnix staging Fil-C 0.687. Checked pointer-memory emission remains here, as does global-data serialization and getter initialization.

Every rule is chosen to be easy to check, not fast; docs/m3.md has them in full.

The frame

Each temporary has an 8-byte slot below %rbp, except a check's proof, which stays in %rax:%rcx for the access fused with it. A p temporary's slot holds its address; its lower lives in a lowers[] entry of the function's filc_frame, which the prologue pushes on thread->top_frame and every return and exception exit pops. Values are never kept in registers across a call or safepoint, so every live capability is always in a slot the GC scans. The prologue zeroes lowers[], so the GC sees no stale lowers.

Temporaries whose closed live intervals are disjoint share a slot (frame_slots.pl). A function that calls setjmp is the exception: each of its temporaries gets a slot of its own.

┌────────────────────────────┐ ← %rbp
│ 8-byte slots: temporaries, │   -8, -16, …
│ phi shadows, thread, aux,  │
│ retbuf, jmp_buf pointers   │
├────────────────────────────┤
│ lowers[NLowers-1]          │
│ …                          │
│ lowers[0]                  │   -FrameBase+16
├────────────────────────────┤
│ origin                     │   -FrameBase+8
│ parent                     │   -FrameBase
├────────────────────────────┤
│ padding to 16 bytes        │
└────────────────────────────┘ ← %rsp = %rbp - Size

Instructions

  • The IR must be checked (ir.pl, pizlonate.pl): each check comes right before the raw access or call it covers, and the two are emitted as one instruction, fusedCheck, Access: the check's sequence, then the operation. Function identity checks come from check_function, not from inferring that an indirect call needs one.
  • Pointer loads and stores go through the object's aux array; a pointer store ensures the aux array and runs the store barrier.
  • flight supplies its address calculation and lower source separately. Emission preserves neither by inference from a p arithmetic operation; pizlonation has already chosen both.
  • alloc is a heap allocation.
  • An edge to pollL runs a pollcheck: a call of filc_pollcheck_slow when the thread's state asks for one.
  • Scalar integer and SSE2 instructions share amd64:compute_op//5. Local mode selects integer immediates before scalar stack caching.
  • Float bits have no lower. At ABI boundaries they travel in XMM registers, or in generic payload words with zero aux (docs/abi-findings.md).

Calls and entries

Calls use the fast convention: the thread, the callee's lower, then the argument words (a buffered return passes its buffer first). A function that throws pops its frame and returns has_exception = 1, in %al or in the return buffer; a caller that sees it propagates it the same way.

Origins preserve the existing can_throw=0: exception flags propagate, but the runtime will not unwind a C++ exception through this frame.

Every function gets a getter, a function object and a generic entry, so its address can be taken; an exported one also gets the global alias for its signature and a global getter, so clang code can call it directly or indirectly.

Variable conventions

VariableMeans
Ctxthe function context (function_ctx/8)
Fnthe amd64 context inside Ctx
Ka word class: w, l, p, s or d
Va value, tmpN or constN
Dthe number of a destination tmpD
Ta load type
Wa store width
S, Fsymbols
Offa byte offset
Forma placed return form, reg or memBytes (target_form/2)
useslists
usesdcgs
usesformat
usesassoc
usespairs
usesir
usesamd64
usescfgedge_label/2
filc_module_asm+Module, -Linesdet

Lines is the asm.pl line list of IR module Module for the Fil-C ABI: each item's code and data, a weak thunk for each function the module calls but does not define, and the GNU-stack note. Throws nanofil_error(Msg) if an item cannot be lowered.

113filc_module_asmModule, Lines ←
filc_module_asmModule, stack, Lines, _

Registers is stack (the reference) or local (validated scalar caching). Reports records each item's caching result, without driver-side state.

117filc_module_asmModule0, Registers, Lines, Reports ←
without_locsModule0, Module
Module = moduleItems
maplistlower_itemModule, Items, Products
lower_thunksModule, Callees
maplistplaced_linesRegisters, Items, Products, LinesPerItem, Reports
appendLinesPerItem, ItemLines
maplistthunk_lines, Callees, LinesPerThunk
appendLinesPerThunk, ThunkLines
appendItemLines, ThunkLines, sectionnote_gnu_stack, Lines
128thunk_linesCallee, Lines ←
phrasethunkCallee, Lines

Complete the ABI product before any instruction selection. Fusion is still target preparation; its separate liveness view preserves indices.

133lower_itemModule, funcN, L, R, Ps, Bs0, Product ←
fused_blocksN, Bs0, Bs, Live
lower_functionModule, funcN, L, R, Ps, Bs, Live, Product
136lower_item_, dataN, L, A, Is, dataN, L, A, Is
138item_linesSelection, Item, Lines ←
phraseitemSelection, Item, Lines
→
true
else
arg1, Item, Name
formatatomMsg, 'Fil-C backend cannot emit ~w', Name
thrownanofil_errorMsg
145placed_linesstack, _, Item, Lines, stack ←
item_linesstack, Item, Lines
146placed_lineslocal, dataN, L, A, Is, Item, Lines, dataN ←
Item = dataN, L, A, Is
item_linesstack, Item, Lines
148placed_lineslocal, Func, Item, Lines, functionName, Report ←
Func = funcName, _, _, Ps, Bs
Item = abi_functionName, _, _, Sig, Frame, _, _, _, _, _
Preserve entire setjmp functions, including unreachable sites, in
both selection and caching. ABI lowering hides the original sites.
→
Setjmp = true
Selection = stack
else
Setjmp = false
Selection = local
item_linesSelection, Item, Original
abi_symbolimplSig, Name, Impl
Adapters, getters and origins have different frames. Only the
implementation before its .size belongs to this placement map.
onceappendBody, sizeImpl|Rest, Original
layoutFrame, Slots, _, _
Frame = frame_, _, Aliases
findallT−K,
memberparamK, T, Ps
or
memberblock_, Phis, Is, _, Bs
memberphiT, K, _, Phis
or
memberI, Is
,
Types0
sortTypes0, Types1
list_to_assocTypes1, Types
findallKey−K,
memberT−Key, Aliases
Key = storagescalar, _
get_assocT, Types, K0
→
K = K0
else
K = unknown
,
Uses
keysortUses, Sorted
group_pairs_by_keySorted, Groups
findallhomeD, Ks,
memberKey−Ks, Groups
get_assocKey, Slots, Off
D is −Off
,
Homes
The checker validates caching against the selected stream; it does
not prove instruction selection itself.
cache_asmlocal, cache_metadataSetjmp, Homes, Body, Cached, Report
appendCached, sizeImpl|Rest, Lines
176cache_temp_classletT, K, _, _, T, K
177cache_temp_classlocal_loadT, K, _, _, _, T, K
178cache_temp_classcallresultT, K, _, _, T, K
179cache_temp_classraw_callresultT, K, _, _, T, K
180cache_temp_classcalltupleRs, _, _, T, K ←
memberresultT, K, Rs
181cache_temp_classraw_calltupleRs, _, _, T, K ←
memberresultT, K, Rs

ABI facts (docs/abi-findings.md), at the pin

abi_symbol+Role, +F, -Symbol

Symbol is the name under which code finds Role of the function or global F: its implementation (the fast entry) and FI alias for signature Sig, its getter, its function object, or its data object and aux array.

189abi_symbolimplSig, F, S ←
formatatomS, 'pizlonatedFIP~w_~w', Sig, F
190abi_symbolentrySig, F, S ←
formatatomS, 'pizlonatedFI~w_~w', Sig, F
191abi_symbolgetter, F, S ←
formatatomS, 'pizlonated_~w', F
192abi_symbolfunction_object, F, S ←
formatatomS, 'pizlonatedFO_~w', F
193abi_symboldata_object, F, S ←
formatatomS, 'pizlonatedDO_~w', F
194abi_symboldata_aux, F, S ←
formatatomS, 'pizlonatedDA_~w', F
field+Struct, +Field, +Base, -Mem

Mem is the operand of Field of the Struct whose address is in register Base. A function object's fields are at its lower.

199fieldStruct, Field, Base, memOff, Base ←
struct_fieldStruct, Field, Off
struct_field
202threadstack_limit0
203threadstate8
204threadtop_frame16
205threadcc_inline_buffer128
206threadcc_inline_aux_buffer384
207function_objectfast_entry0
208function_objectgeneric_entry8
209function_objectsignature16
aux_bits+Flags, -Bits

Bits are the flags Flags in an aux word, whose low 48 bits are the aux pointer (aux_pointer_mask/1) and whose high 16 the flags. The special type is a field of the flags.

214aux_bitsFlags, Bits ←
foldlflag_or, Flags, 0, Sum
Bits is Sum << 48
218flag_orFlag, Sum0, Sum ←
object_flagFlag, Bit
Sum is Sum0 \/ Bit
object_flag
222global0x1
223readonly0x2
224global_aux0x10

the aux array is static data

225function0x80

special type 1, function

226special_type0x780

the special type field, bits 7-10

228aux_pointer_mask0xffffffffffff

Frame layout

Place the already chosen payloads, roots and aliases below %rbp.

233layoutframePlain, Lowers, Aliases, Slots, FrameBase, Size ←
lengthLowers, NLowers
empty_assocSlots0
foldlplain_slot, Plain, Slots0−0, Slots1−PlainBytes
FrameBase is PlainBytes + 16 + 8 × NLowers
foldllower_slotFrameBase, Lowers, Slots1−0, Slots2−_
foldltemp_alias, Aliases, Slots2, Slots
Size is FrameBase + 15//16 × 16
242temp_aliasT−Key, Slots0, Slots ←
get_assocKey, Slots0, Off
put_assocT, Slots0, Off, Slots

Named object storage is not a temporary slot and is never reused. Payload is 16-aligned; aux is a count header followed by lower words.

247plain_slotlocalName, Size, Slots0−Off0, Slots−End ←
!
Padded is Size + 15//16 × 16
Payload is Off0 + Padded + 15//16 × 16
Aux is Payload + Padded + 8
End = Aux
put_assoclocalName, Slots0, localPayload, Aux, Size, Padded, Slots
252plain_slotKey, Slots0−Off0, Slots−Off ←
Off is Off0 + 8
put_assocKey, Slots0, Off, Slots
lower_slot+FrameBase, +Key, +Slots0−I0, −Slots−I

Slots maps Key to lowers[I0] of the filc_frame at -FrameBase(%rbp).

258lower_slotFrameBase, Key, Slots0−I0, Slots−I ←
Off is FrameBase−16−8 × I0
I is I0 + 1
put_assocKey, Slots0, Off, Slots

The function context

function_ctx(+Name, +Ret, +Slots, +Blocks, +Size, +FrameBase, +Selection, -Ctx): Ctx = ctx(Fn, Size, FrameBase, Labels, Selection) is the context of function Name, where Fn = f(Name, Ret, Slots, Blocks) is the context amd64's load//4 and compute_op//4 take. Labels maps each block label to its phis, so an edge finds them without searching Blocks.

270function_ctxName, Ret, Slots, Blocks, Size, FrameBase, Selection, Ctx ←
findallLabel−Phis, memberblockLabel, Phis, _, _, Blocks, LabelBlocks
list_to_assocLabelBlocks, Labels
Ctx = ctxfName, Ret, Slots, Blocks, Size, FrameBase, Labels, Selection
275ctx_fnctxFn, _, _, _, _, Fn
277ctx_namectxfName, _, _, _, _, _, _, _, Name
279ctx_sizectx_, Size, _, _, _, Size
281ctx_frame_basectx_, _, FrameBase, _, _, FrameBase
283ctx_labelsctx_, _, _, Labels, _, Labels
285ctx_selectionctx_, _, _, _, Selection, Selection
ctx_slot+Ctx, +Key, -Off

Key's slot is at -Off(%rbp).

288ctx_slotctxf_, _, Slots, _, _, _, _, _, Key, Off ←
get_assocKey, Slots, Off

The store of register Reg into Key's slot.

292reg_slot_storeReg, Key, Ctx ⟶
ctx_slotCtx, Key, Off
Disp is −Off
insmov, q, regReg, memDisp, rbp

The load of Key's slot into register Reg.

298slot_reg_loadKey, Reg, Ctx ⟶
ctx_slotCtx, Key, Off
Disp is −Off
insmov, q, memDisp, rbp, regReg

Local labels: A is the label atom in each relation.

A label shared by the whole function, e.g. exc for exception exits.

306special_labelCtx, Tag, A ←
ctx_nameCtx, Name
formatatomA, '.L~w..~w', Name, Tag

The label of the block named Label.

311block_labelCtx, Label, A ←
ctx_nameCtx, Name
formatatomA, '.L~w.~w', Name, Label

A label inside the code of instruction Index (or a jump) in Block.

316local_labelCtx, Block, Index, Tag, A ←
ctx_nameCtx, Name
formatatomA, '.L~w.~w..~w.~w', Name, Block, Index, Tag

The frame's origin: c (calls, can_catch) or n (pollchecks and checks).

321origin_labelName, Which, A ←
formatatomA, '.L~w..origin_~w', Name, Which

Functions

The lines of a module item, a function or a data object.

327itemSelection, Func ⟶
Func = abi_function_, _, _, _, _, _, _, _, _, _
functionSelection, Func
330item_, dataName, Linkage, _, Items ⟶
data_objectName, Linkage, Items

A function: its implementation (prologue, blocks, the shared exception exit and failure blocks), then its function object and origins.

335functionSelection, abi_functionName, Linkage, Ret, Sig, Frame, Entry, Blocks, Exit, Object, Origins ⟶
layoutFrame, Slots, FrameBase, Size
function_ctxName, Ret, Slots, Blocks, Size, FrameBase, Selection, Ctx
abi_symbolimplSig, Name, Impl
access_check_kindsBlocks, CheckKinds
special_labelCtx, exc, Exc
sectiontext, p2align4
linkage_globlLinkage, Impl
typeImpl, function, labelImpl
abi_actionsEntry, entry, entry, Ctx
blocksBlocks, Ctx
labelExc
abi_actionsExit, exit, exit, Ctx
check_fail_blocksCheckKinds, Ctx
sizeImpl
body_function_objectObject, Name, Linkage, Impl
originsName, Origins, CheckKinds

fused_blocks(+Fn, +Blocks0, -Blocks, -LiveBlocks): Blocks are the checked Blocks0 with each check and the raw access after it, which reads its proven address, fused into fused(Check, Access) at one index, so labels and frame slots number instructions as they did before checks were explicit. Access reads the checked pointer P itself: a proof is a register value (%rax:%rcx after the check) and needs no slot. LiveBlocks have the bare accesses, for liveness and layout, which so keep P live through the access, as the reload after ensure-aux needs. Function proofs fuse with raw_call in the same way: the original pointer and all arguments stay live through the call, and neither proof gets a frame slot. Throws unless the IR is checked and every cycle polls.

367fused_blocksFn, Blocks0, Blocks, LiveBlocks ←
→
true
else
throw_fnFn, 'a cycle without a poll edge; run pizlonate first'
maplistfused_blockFn, Blocks0, Blocks
maplistlive_block, Blocks, LiveBlocks
374fused_blockFn, blockL, Phis, Insts0, Jump, blockL, Phis, Insts, Jump ←
fused_instsInsts0, Fn, Insts
377fused_insts[], _, []
378fused_instsInst0|Insts0, Fn, Inst|Insts ←
fused_instInst0, Insts0, Fn, Inst, Insts1
fused_instsInsts1, Fn, Insts
382fused_instlettmpQ, a, Check, [], Access0|Insts, Fn, fusedCheck, Access, Insts ←
Check = check_localName, Off, _, _, _
!
proven_local_accessAccess0, Q, localName, Off, Access
access_pointerAccess, _, 0
→
true
else
throw_fnFn, 'a local check not followed by its local access'
389fused_instlettmpQ, a, Check, P, Access0|Insts, Fn, Inst, Insts ←
!
proven_accessAccess0, Q, P, Access
→
Inst = fusedCheck, Access
else
throw_fnFn, 'a check not followed by the access it proves'
access_check//2 checks [P, P+Size) for alignment 1 or 8, and a raw
access emits at offset 0. subq's immediate is signed 32-bit: a
larger check needs a different native representation, not truncation.
Check = check0, Size, _, Align
memberchkAlign, 1, 8
integerSize
Size > 0
Size ≤ 2147483647
access_pointerAccess, _, 0
→
true
else
throw_fnFn, 'a check or offset access_check//2 cannot emit yet'
402fused_instlettmpQ, f, check_function, P, Insts0, Fn, fusedcheck_function, callRes, P, Args, Insts ←
!
Insts0 = raw_callRes, tmpQ, Args|Insts
→
true
else
throw_fnFn, 'a function check not followed by its raw call'
407fused_instInst, Insts, Fn, Inst, Insts ←
→
throw_fnFn, 'an unchecked access; run pizlonate first'
→
throw_fnFn, 'an implicit pointer operation; run pizlonate first'
else
true
proven_access+Access0, +Q, +P, -Access

Access0 is a raw access at tmp(Q) and Access is the same at P.

417proven_accessletD, K, raw_loadT, Off, tmpQ, Q, P, letD, K, raw_loadT, Off, P ←
T ≢ p
419proven_accessraw_storeW, Off, V, tmpQ, Q, P, raw_storeW, Off, V, P ←
W ≢ p
421proven_accessletD, p, raw_load_pointerOff, Es, tmpQ, Q, P, letD, p, raw_load_pointerOff, Es, P ←
424proven_accessraw_store_pointerOff, V, tmpQ, Es, Q, P, raw_store_pointerOff, V, P, Es ←
428proven_local_accessletD, p, raw_load_pointerOff, Es, tmpQ, Q, P, letD, p, raw_load_pointerOff, Es, P ←
431proven_local_accessraw_store_pointerOff, V, tmpQ, Es, Q, P, raw_store_pointerOff, V, P, Es ←
pointer_memory_effectslocal_store, Es
434proven_local_accessletD, K, raw_loadT, Off, tmpQ, Q, P, letD, K, raw_loadT, Off, P ←
T ≢ p
436proven_local_accessraw_storeW, Off, V, tmpQ, Q, P, raw_storeW, Off, V, P ←
W ≢ p
access_pointer+Access, -P, -Off

the fused Access is at P + Off.

access_pointer
440let_, _, raw_load_, Off, PPOff
441raw_store_, Off, _, PPOff
442let_, p, raw_load_pointerOff, _, PPOff
443raw_store_pointerOff, _, P, _POff
444access_pointerAccess, P ←
access_pointerAccess, P, _
unchecked_accesslet_, _, load_, _store_, _, _call_, tmp_, _raw_call_, _, _let_, _, raw_load_, _, _raw_store_, _, _, _let_, _, raw_load_pointer_, _, _raw_store_pointer_, _, _, _local_load_, _, _, _, _local_store_, _, _, _
457live_blockblockL, Phis, Insts0, Jump, blockL, Phis, Insts, Jump ←
maplistlive_inst, Insts0, Insts

Layout sees exactly the former whole-pointer operation at this index. In particular both original p operands survive every internal helper.

462live_instfused_, letD, p, raw_load_pointerOff, _, P, letD, p, raw_loadp, Off, P ←
!
464live_instfused_, raw_store_pointerOff, V, P, _, raw_storep, Off, V, P ←
!
466live_instInst0, Inst ←
Inst0 = fused_, Access
→
Inst = Access
else
Inst = Inst0
469throw_fnFn, Why ←
formatatomMsg, 'Fil-C backend, in ~w: ~w', Fn, Why
thrownanofil_errorMsg
473setjmp_snapshots[], _, _ ⟶
[]
474setjmp_snapshotsD|Ds, Bytes, Ctx ⟶
slot_reg_loadthread, rdi, Ctx
insmov, q, immBytes, regrsi, inscall, none, pltfilc_allocate, inslea, q, mem16, rax, regrdx
reg_slot_storerdx, lowersetjmp_snapshotD, Ctx
setjmp_snapshotsDs, Bytes, Ctx
483body_function_objectgeneric_onlyAdapter, Name, Linkage, Impl ⟶
variadic_objectName, Linkage, Adapter, Impl
485body_function_objectfast_and_genericSig, Adapter, Name, Linkage, Impl ⟶
function_objectName, Linkage, Adapter, Sig, Impl

The return protocol is already chosen; this is only its native size.

489target_formregisters, reg
490target_formbufferN, memBytes ←
Bytes is 8 + 8 × N + 15//16 × 16
492abi_actions[], _, _, _ ⟶
[]
493abi_actionsA|As, I, B, Ctx ⟶
abi_actionA, I, B, Ctx
abi_actionsAs, I, B, Ctx
496abi_actionnative_frameReturn, _, _, Ctx ⟶
ctx_sizeCtx, Size
target_formReturn, Form
inspush, q, regrbp, insmov, q, regrsp, regrbp, inssub, q, immSize, regrsp
502abi_actionstack_check, _, _, _ ⟶
fieldthread, stack_limit, rdi, Limit
inscmp, q, regrsp, Limit, insjae, none, pltfilc_stack_overflow_failure
506abi_actionsave_thread, _, _, Ctx ⟶
reg_slot_storerdi, thread, Ctx
507abi_actionsave_returnReturn, _, _, Ctx ⟶
target_formReturn, Form
retbuf_storeForm, Ctx
509abi_actionzero_rootsN, _, _, Ctx ⟶
511abi_actionpush_frameWhich, _, _, Ctx ⟶
NegFrameBase is −Base
fieldthread, top_frame, rdi, Top
insmov, q, Top, regrax, insmov, q, regrax, memNegFrameBase, rbp
origin_storeCtx, Which
inslea, q, memNegFrameBase, rbp, regrax, insmov, q, regrax, Top
519abi_actionreceiveReturn, Ts, _, _, Ctx ⟶
target_formReturn, Form
typed_locationsTs, Form, Ls, _, _
typed_incomingTs, Ls, Ctx
522abi_actionsnapshotsSites, Keys, _, _, Ctx ⟶
lengthKeys, N
Bytes is 8 × N
setjmp_snapshotsSites, Bytes, Ctx
524abi_actioninitialize_localName, _, _, Ctx ⟶
ctx_slotCtx, localName, localPayload, Aux, _, Padded
P is −Payload
A is −Aux
Words is Padded//8
zero_wordsP, Words
Lowers is A + 8
zero_wordsLowers, Words
insmov, q, immWords, memA, rbp, inslea, q, memA, rbp, regrax
reg_slot_storerax, stack_auxName, Ctx
532abi_actionpop_frame, _, _, Ctx ⟶
533abi_actionexceptionReturn, _, _, Ctx ⟶
target_formReturn, Form
insleave, none, [], insret, none, []
536abi_actionoriginWhich, _, _, Ctx ⟶
origin_storeCtx, Which
537abi_actionreserve_resultReturn, _, _, _ ⟶
539abi_actionrelease_resultReturn, _, _, _ ⟶
541abi_actioninvokeTarget, Return, Words, _, _, Ctx ⟶
target_formReturn, Form
target_operandTarget, Operand
fast_callForm, Words, directOperand, Ctx
544abi_actionresultReturn, Channels, _, _, Ctx ⟶
target_formReturn, Form
fast_resultForm, Channels, Ctx
546abi_actiondispatchP, Sig, Return, Words, Result, Size, Cells, GenericResult, I, B, Ctx ⟶
special_labelCtx, notfn, NotFn
target_formReturn, Form
reg_slot_storercx, aux, Ctx
indirect_callSig, Form, Words, Result, Size, Cells, GenericResult, I, B, Ctx
550abi_actiongetterTarget, Which, D, _, _, Ctx ⟶
ctx_nameCtx, Name
origin_labelName, Which, Origin
target_operandTarget, Getter
slot_reg_loadthread, rdi, Ctx
inslea, q, ripOrigin, regrsi, inscall, none, Getter, insmov, q, regrdx, regrcx
557abi_actionsnapshot_cursorSnapshot, Off, D, _, _, Ctx ⟶
ctx_fnCtx, Fn
flight_loadSnapshot, Ctx
loadconstOff, l, d, Fn
insadd, q, regrdx, regrax
561abi_actionconsume_vaK, P, Size, D, I, B, Ctx ⟶
insmov, q, regrax, regrdi, insmov, q, regrcx, regrsi, insmov, l, immSize, regedx, insmov, l, immSize, regecx, inscall, none, pltfilc_get_next_ptr_bytes_for_va_arg
va_arg_loadK, D, I, B, Ctx
567abi_actionreturns_twiceD, Kind, Buf, Mask, Keys, I, B, Ctx ⟶
setjmpD, Kind, Buf, Mask, Keys, I, B, Ctx
569abi_actionreturn_valueK, V, _, _, Ctx ⟶
ret_valueK, V, Ctx
570abi_actionreturn_registersV1, V2, _, _, Ctx ⟶
ctx_fnCtx, Fn
loadV1, l, d, Fn
loadV2, l, c, Fn
572abi_actionreturn_bufferWords, _, _, Ctx ⟶
slot_reg_loadretbuf, rax, Ctx
buffer_wordsWords, 8, Ctx
574abi_actionsuccessregisters, _, _, _ ⟶
insxor, l, regeax, regeax, insleave, none, [], insret, none, []
576abi_actionsuccess_buffer, _, _, _ ⟶
insmov, b, imm0, mem0, rax
578abi_actionnative_return, _, _, _ ⟶
insleave, none, [], insret, none, []
580target_operandimplementationF, Sig, symS ←
abi_symbolimplSig, F, S
581target_operandentryF, Sig, symS ←
abi_symbolentrySig, F, S
582target_operandlocal_getterF, symS ←
abi_symbolgetter, F, S
583target_operandexternal_getterF, pltS ←
abi_symbolgetter, F, S

A buffered return's entry has the buffer in %rdi and the thread in %rsi: the buffer goes to %rax and the thread to %rdi.

587entry_regs_shiftreg ⟶
[]
588entry_regs_shiftmem_ ⟶
insmov, q, regrdi, regrax, insmov, q, regrsi, regrdi

The buffer of a buffered return, from %rax into its slot.

593retbuf_storereg, _ ⟶
[]
594retbuf_storemem_, Ctx ⟶
reg_slot_storerax, retbuf, Ctx

The zeroing of the N entries of lowers[], so the GC sees no stale lowers.

598lowers_zeroingN, FrameBase ⟶
N > 0
→
insxor, l, regeax, regeax
N1 is N−1
numlist0, N1, Is
lower_entry_storesIs, FrameBase
else
[]

The store of %rax into lowers[I] for each I in Is.

608lower_entry_stores[], _ ⟶
[]
609lower_entry_storesI|Is, FrameBase ⟶
Off is 16 + 8 × I−FrameBase
insmov, q, regrax, memOff, rbp
lower_entry_storesIs, FrameBase
614zero_words_, 0 ⟶
!
[]
615zero_wordsOff, N ⟶
insmov, q, imm0, memOff, rbp
Next is Off + 8
Rest is N−1
zero_wordsNext, Rest

The store of the c or n origin (origin_label/3) into the filc_frame.

620origin_storeCtx, Which ⟶
ctx_nameCtx, Name
ctx_frame_baseCtx, FrameBase
Off is 8−FrameBase
origin_labelName, Which, Origin
inslea, q, ripOrigin, regrax, insmov, q, regrax, memOff, rbp

The pop of the filc_frame: thread->top_frame back to its parent.

629frame_popCtx ⟶
ctx_frame_baseCtx, FrameBase
NegFrameBase is −FrameBase
fieldthread, top_frame, rsi, Top
slot_reg_loadthread, rsi, Ctx
insmov, q, memNegFrameBase, rbp, regrdi, insmov, q, regrdi, Top

has_exception = 1, in %al or in the return buffer.

638exception_flagreg, _ ⟶
insmov, b, imm1, regal
640exception_flagmem_, Ctx ⟶
slot_reg_loadretbuf, rax, Ctx
insmov, b, imm1, mem0, rax

The failure block of function_check//1, if the function calls through a pointer.

646not_function_blockBlocks, Ctx ⟶
memberblock_, _, Insts, _, Blocks
memberabiActions, Insts
memberchkdispatch_, _, _, _, _, _, _, _, Actions
→
special_labelCtx, notfn, NotFn
labelNotFn, insmov, q, regrax, regrdi, insmov, q, regrcx, regrsi, inscall, none, pltfilc_check_function_call_fail, insud2, none, []
else
[]

The same registers by their amd64 short names, for load//4.

660form_short_regsreg, d, c, r8, r9
661form_short_regsmem_, c, r8, r9

Word I of a generic call's arguments or results is at thread offset Addr, word I of the inline buffer, with its lower at Lower, word I of the inline aux buffer.

666generic_offsetsI, Addr, Lower ←
struct_fieldthread, cc_inline_buffer, Buffer
struct_fieldthread, cc_inline_aux_buffer, AuxBuffer
Addr is Buffer + 8 × I
Lower is AuxBuffer + 8 × I
672channel_offsetdataI, Off ←
673channel_offsetauxI, Off ←
674packet_offsetspacketCopies, Zeros, packetOffsets, ZeroOffsets ←
maplistchannel_offset, Copies, Offsets
maplistchannel_offset, Zeros, ZeroOffsets

Stack space for a buffered return, around a call.

678ret_buffer_reservationreg ⟶
[]
679ret_buffer_reservationmemBytes ⟶
inssub, q, immBytes, regrsp
681ret_buffer_releasereg ⟶
[]
682ret_buffer_releasememBytes ⟶
insadd, q, immBytes, regrsp

The padding, Pad = 0 or 1 words, that keeps %rsp 16-aligned at a call that pushes an odd number of words.

686align_pad0 ⟶
[]
687align_pad1 ⟶
inssub, q, imm8, regrsp

The release of Bytes of pushed stack words, if any.

690stack_releaseBytes ⟶
Bytes > 0
→
insadd, q, immBytes, regrsp
else
[]

Blocks and jumps

Each block: its label, instructions and jump.

699blocks[], _ ⟶
[]
700blocksblockLabel, _, Insts, Jump|Blocks, Ctx ⟶
block_labelCtx, Label, A
labelA
instsInsts, 0, Label, Ctx
jumpJump, Label, Ctx
blocksBlocks, Ctx

The code of the jump that ends block From.

708jumpgotoTo, From, Ctx ⟶
edgeFrom, To, j, Ctx
710jumpbranchV, True, False, From, Ctx ⟶
ctx_fnCtx, Fn
local_labelCtx, From, jnz, false, FalseLabel
loadV, w, a, Fn
instest, l, regeax, regeax, insjz, none, symFalseLabel
edgeFrom, True, t, Ctx
labelFalseLabel
edgeFrom, False, f, Ctx
719jumpabi_returnActions, B, Ctx ⟶
abi_actionsActions, ret, B, Ctx
720jumpunreachable, _, _ ⟶
insud2, none, []

The returned value V of class K, in %rdx, and its lower in %rcx for p.

724ret_valuep, V, Ctx ⟶
ctx_fnCtx, Fn
loadV, l, d, Fn
lower_reg_loadV, rcx, Ctx
728ret_valuew, V, Ctx ⟶
ctx_fnCtx, Fn
loadV, w, d, Fn
731ret_valuel, V, Ctx ⟶
ctx_fnCtx, Fn
loadV, l, d, Fn
734ret_valueK, V, Ctx ⟶
loadV, K, a, Fn
to_xmmK, a, xmm0

The words of a buffered return, into the buffer at %rax.

739buffer_words[], _, _ ⟶
[]
740buffer_wordswf_, Word|Words, Off, Ctx ⟶
ctx_fnCtx, Fn
reg_nameR, l, Reg
buffer_word_loadWord, R, Fn, Ctx
insmov, q, regReg, memOff, rax
Next is Off + 8
buffer_wordsWords, Next, Ctx
buffer_register
745lower_c
746addr_d
747val_, _d

Tuple payloads occupy full eightbyte slots even for a w element.

749buffer_word_loadval_, V, R, Fn, _ ⟶
loadV, l, R, Fn
750buffer_word_loadaddrV, R, Fn, _ ⟶
loadV, l, R, Fn
751buffer_word_loadlowerV, R, _, Ctx ⟶
reg_nameR, l, Reg
lower_reg_loadV, Reg, Ctx

Phi copies for the edge to Target, a label or poll(Label), then the pollcheck if Target asks for one, then the jump.

756edgeFrom, Target, Tag, Ctx ⟶
edge_labelTarget, To
ctx_labelsCtx, Labels
get_assocTo, Labels, Phis
block_labelCtx, To, ToLabel
phi_readsPhis, From, Ctx
phi_writesPhis, Ctx
edge_pollTarget, From, Tag, Ctx
insjmp, none, symToLabel
766edge_pollTarget, From, Tag, Ctx ⟶
Target = poll_
→
pollcheckCtx, From, Tag
else
[]

The pollcheck: a call of filc_pollcheck_slow if the thread's state asks for it.

774pollcheckCtx, Block, Tag ⟶
ctx_nameCtx, Name
local_labelCtx, Block, Tag, poll, NoPoll
origin_labelName, n, Origin
fieldthread, state, rdi, State
slot_reg_loadthread, rdi, Ctx
instest, b, imm14, State, insjz, none, symNoPoll, inslea, q, ripOrigin, regrsi, inscall, none, pltfilc_pollcheck_slow, labelNoPoll

The parallel copy of an edge's phis: first every incoming value into its phi's shadow slots (phi_reads//3), then every shadow into the phi (phi_writes//2).

789phi_reads[], _, _ ⟶
[]
790phi_readsphitmpD, K, Pairs|Phis, From, Ctx ⟶
memberchkFrom−V, Pairs
phi_readK, V, D, Ctx
phi_readsPhis, From, Ctx

The incoming value V, of class K, into the shadow slots of phi tmp(D).

796phi_readp, V, D, Ctx ⟶
ctx_fnCtx, Fn
loadV, l, a, Fn
reg_slot_storerax, shadowD, Ctx
lower_reg_loadV, rax, Ctx
reg_slot_storerax, lowershadowD, Ctx
802phi_readw, V, D, Ctx ⟶
ctx_fnCtx, Fn
loadV, w, a, Fn
reg_slot_storerax, shadowD, Ctx
806phi_readl, V, D, Ctx ⟶
ctx_fnCtx, Fn
loadV, l, a, Fn
reg_slot_storerax, shadowD, Ctx
810phi_readK, V, D, Ctx ⟶
loadV, K, a, Fn
reg_slot_storerax, shadowD, Ctx

The second half of the parallel copy: each phi's shadow into the phi.

815phi_writes[], _ ⟶
[]
816phi_writesphitmpD, K, _|Phis, Ctx ⟶
slot_reg_loadshadowD, rax, Ctx
reg_slot_storerax, tmpD, Ctx
phi_writesPhis, Ctx

For a p phi tmp(D), its shadow lower into its lower.

823phi_lower_writep, D, Ctx ⟶
slot_reg_loadlowershadowD, rax, Ctx
reg_slot_storerax, lowertmpD, Ctx
826phi_lower_writew, _, _ ⟶
[]
827phi_lower_writel, _, _ ⟶
[]
828phi_lower_writes, _, _ ⟶
[]
829phi_lower_writed, _, _ ⟶
[]

The lower of a p value: its lowers[] entry, or 0 for a constant.

832lower_reg_loadtmpN, Reg, Ctx ⟶
slot_reg_loadlowertmpN, Reg, Ctx
833lower_reg_loadconst_, Reg, _ ⟶
insmov, q, imm0, regReg

A p value's address into %rax and lower into %rcx.

836flight_loadV, Ctx ⟶
ctx_fnCtx, Fn
loadV, l, a, Fn
lower_reg_loadV, rcx, Ctx

The flight pointer in %rax:%rcx into tmp(D) and its lower.

842flight_storeD, Ctx ⟶
reg_slot_storerax, tmpD, Ctx
reg_slot_storercx, lowertmpD, Ctx

Instructions

The code of each instruction. Invariant: Insts are the instructions of Block from index Index on.

850insts[], _, _, _ ⟶
[]
851instsInst|Insts, Index, Block, Ctx ⟶
instInst, Index, Block, Ctx
Index1 is Index + 1
instsInsts, Index1, Block, Ctx
inst+Inst, +Index, +Block, +Ctx//

the code of instruction Inst, the Indexth of block Block. Instructions go by their op's kind (ir.pl), stores and calls by their width and callee.

859instlettmpD, K, Op, Args, Index, Block, Ctx ⟶
op_kindOp, Kind
kind_instKind, K, Op, Args, D, Index, Block, Ctx
862instflighttmpD, Op, A|Args, Lower, _, _, Ctx ⟶
867instfusedcheck_, Size, Rights, Align, Access, Index, Block, Ctx ⟶
rights_writeRights, Write
access_checkkSize, Write, Align, Ctx
raw_accessAccess, Index, Block, Ctx
873instfusedcheck_localName, Off, Size, Rights, Align, Access, I, B, Ctx ⟶
rights_writeRights, Write
local_checkName, Off, kSize, Write, Align, I, B, Ctx
local_raw_accessAccess, I, B, Ctx
877instabiActions, Index, Block, Ctx ⟶
abi_actionsActions, Index, Block, Ctx

Check exact logical bounds without manufacturing a heap lower. Offset and size are the stack reporter's arguments. Address formation happens only after the full range/alignment check, even for constant accesses.

882local_checkName, Off, Kind, I, B, Ctx ⟶
Kind = kBytes, _, Align
Mask is Align−1
ctx_slotCtx, localName, localPayload, Aux, Size, _
P is −Payload
A is 8−Aux
Limit is Size−Bytes
local_labelCtx, B, I, localfail, Fail
local_labelCtx, B, I, localok, Good
ctx_nameCtx, FnName
check_origin_labelFnName, Kind, Origin
ctx_fnCtx, Fn
loadconstOff, l, a, Fn
loadconstSize, l, c, Fn
loadconstLimit, l, d, Fn
instest, q, regrdx, regrdx, insjs, none, symFail, inscmp, q, regrdx, regrax, insja, none, symFail, instest, q, immMask, regrax, insjnz, none, symFail, insjmp, none, symGood, labelFail, insmov, q, regrax, regrdi, insmov, q, regrcx, regrsi, inslea, q, ripOrigin, regrdx, inscall, none, pltfilc_optimized_stack_access_check_fail, insud2, none, [], labelGood, inslea, q, memA, rbp, rax, regrdx, inslea, q, memP, rbp, rax, regrax
kind_inst+Kind, +K, +Op, +Args, +D, +Index, +Block, +Ctx//

as inst//4, for tmp(D) =K Op Args with Op of Kind. Integer instructions go to amd64:compute_op//5; the pointer ones are by K, or (copy at p) by the operand.

907kind_instfloat_convert, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
908kind_instfloat_to_int, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
909kind_instint_to_float, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
910kind_instcast, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
911kind_instadditive, K, Op, Args, D, _, _, Ctx ⟶
additive_instK, Op, Args, D, Ctx
913kind_instalu, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
915kind_instshift, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
917kind_instneg, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
919kind_instcopy, K, Op, Args, D, _, _, Ctx ⟶
copy_instK, Op, Args, D, Ctx
921kind_instptoi, l, _, P, D, _, _, Ctx ⟶
ctx_fnCtx, Fn
loadP, l, a, Fn
reg_slot_storerax, tmpD, Ctx
925kind_instcmp, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
927kind_instext, K, Op, Args, D, _, _, Ctx ⟶
integer_instOp, K, Args, D, Ctx
929kind_installoc, p, allocAlign, N, D, _, _, Ctx ⟶
ctx_fnCtx, Fn
loadN, l, si, Fn
slot_reg_loadthread, rdi, Ctx
Align ≡ 16
→
insmov, l, imm16, regedx, inscall, none, pltfilc_allocate_with_alignment
else
inscall, none, pltfilc_allocate
inslea, q, mem16, rax, regrax, insmov, q, regrax, regrcx
942setjmpD, KindNo, Buf, Mask, Keys, Index, Block, Ctx ⟶
ctx_fnCtx, Fn
ctx_slotCtx, lowertmphiddensetjmp_bufD, Off
NegOff is −Off
local_labelCtx, Block, Index, setjmp_done, Done
slot_reg_loadlowersetjmp_snapshotD, rdx, Ctx
setjmp_payload_copysave, Keys, 0, Ctx
slot_reg_loadthread, rdi, Ctx
inslea, q, memNegOff, rbp, regrsi, insmov, l, immKindNo, regedx
loadMask, w, c, Fn
inscall, none, pltfilc_jmp_buf_recreate, insmov, q, regrax, regrcx
flight_storehiddensetjmp_bufD, Ctx
checked_pointer_storetmphiddensetjmp_bufD, Buf, Index, Block, Ctx
slot_reg_loadlowertmphiddensetjmp_bufD, rdi, Ctx
inscall, none, plt'_setjmp', instest, l, regeax, regeax, insjz, none, symDone
slot_reg_loadlowersetjmp_snapshotD, rdx, Ctx
setjmp_payload_copyrestore, Keys, 0, Ctx
labelDone
reg_slot_storerax, tmpD, Ctx

RDX is the snapshot payload; RCX is scratch. EAX's full native int survives restoration, which contains no calls, polls or checked loads.

967setjmp_payload_copy_, [], _, _ ⟶
[]
968setjmp_payload_copyDirection, Key|Keys, Off, Ctx ⟶
payload_word_copyDirection, Key, Off, Ctx
Next is Off + 8
setjmp_payload_copyDirection, Keys, Next, Ctx
972payload_word_copysave, Key, Off, Ctx ⟶
slot_reg_loadKey, rcx, Ctx
insmov, q, regrcx, memOff, rdx
975payload_word_copyrestore, Key, Off, Ctx ⟶
insmov, q, memOff, rdx, regrcx
reg_slot_storercx, Key, Ctx
integer_inst+Op, +K, +Args, +D, +Ctx//

the code of the integer instruction tmp(D) =K Op Args.

981integer_instOp, K, Args, D, Ctx ⟶
ctx_fnCtx, Fn
ctx_selectionCtx, Selection
compute_opSelection, Op, K, Args, Fn
reg_slot_storerax, tmpD, Ctx

The helper returns payload and auxiliary *addresses*, not a flight pointer. Consume both without a safepoint, then root the loaded lower.

988va_arg_loadw, D, _, _, Ctx ⟶
insmov, l, mem0, rax, regeax
reg_slot_storerax, tmpD, Ctx
991va_arg_loadl, D, _, _, Ctx ⟶
insmov, q, mem0, rax, regrax
reg_slot_storerax, tmpD, Ctx
994va_arg_loads, D, I, B, Ctx ⟶
va_arg_loadw, D, I, B, Ctx
995va_arg_loadd, D, I, B, Ctx ⟶
va_arg_loadl, D, I, B, Ctx
996va_arg_loadp, D, Index, Block, Ctx ⟶
local_labelCtx, Block, Index, va_none, None
local_labelCtx, Block, Index, va_have, Have
insxor, l, regecx, regecx, instest, q, regrdx, regrdx, insjz, none, symNone, insmov, q, mem0, rdx, regrcx, instest, b, imm1, regcl, insjz, none, symHave, insand, q, imm-2, regrcx, insmov, q, mem8, rcx, regrcx, labelHave, labelNone, insmov, q, mem0, rax, regrax
additive_inst+K, +Op, +Args, +D, +Ctx//

scalar add or sub.

1012additive_instw, Op, Args, D, Ctx ⟶
integer_instOp, w, Args, D, Ctx
1013additive_instl, Op, Args, D, Ctx ⟶
integer_instOp, l, Args, D, Ctx
1014additive_instK, Op, Args, D, Ctx ⟶
integer_instOp, K, Args, D, Ctx
copy_inst+K, +Op, +Args, +D, +Ctx//

a copy at K.

1018copy_instw, Op, Args, D, Ctx ⟶
integer_instOp, w, Args, D, Ctx
1019copy_instl, Op, Args, D, Ctx ⟶
integer_instOp, l, Args, D, Ctx
1020copy_instK, Op, Args, D, Ctx ⟶
integer_instOp, K, Args, D, Ctx

Flight's inputs are all read before its destination is written. The second address uses %rdx, not the scalar ALU's %rcx, which holds the explicitly selected lower. No call or safepoint splits the pair.

1026flight_address_loadaddressP, R, Ctx ⟶
!
ctx_fnCtx, Fn
loadP, l, R, Fn
1028flight_address_loadV, R, Ctx ⟶
ctx_fnCtx, Fn
loadV, l, R, Fn
1031flight_lower_loadlowerP, Ctx ⟶
lower_reg_loadP, rcx, Ctx
1032flight_lower_loadnone, _ ⟶
insxor, l, regecx, regecx
1034flight_calculationcopy, [], _ ⟶
[]
1035flight_calculationOp, X, Ctx ⟶
memberchkOp, add, sub
insOp, q, regrdx, regrax
raw_access+Access, +Index, +Block, +Ctx//

the code of the raw Access at P, the Indexth instruction of Block, after its check left P in %rax and its lower in %rcx.

1043raw_accesslettmpD, K, raw_loadT, 0, _, Index, Block, Ctx ⟶
raw_loadT, K, D, Index, Block, Ctx
1045raw_accessraw_storeW, 0, V, P, Index, Block, Ctx ⟶
raw_storeW, V, P, Index, Block, Ctx
1047raw_accesslettmpD, p, raw_load_pointer0, Effects, _, I, B, Ctx ⟶
pointer_load_effectsEffects, I, B, Ctx
1050raw_accessraw_store_pointer0, V, P, Effects, I, B, Ctx ⟶
pointer_store_effectsEffects, V, P, I, B, Ctx

%rax is the checked payload address, %rdx its explicit aux word. Neither register is an ordinary root. Only loaded/stored *contents* have heap lowers, and no helper or safepoint splits these operations.

1056local_raw_accesslettmpD, p, raw_load_pointer0, Es, _, _, _, Ctx ⟶
1058local_raw_accessraw_store_pointer0, V, _, Es, _, _, Ctx ⟶
1060local_raw_accessAccess, I, B, Ctx ⟶
raw_accessAccess, I, B, Ctx
1062local_load_effects[] ⟶
[]
1063local_load_effectsE|Es ⟶
1064local_load_effectaux_read ⟶
insmov, q, mem0, rdx, regrcx
1065local_load_effectaddress_read ⟶
insmov, q, mem0, rax, regrax
1067local_store_effects[], _, _ ⟶
[]
1068local_store_effectsE|Es, V, Ctx ⟶
1070local_store_effectlower_write, V, Ctx ⟶
lower_reg_loadV, rcx, Ctx
insmov, q, regrcx, mem0, rdx
1072local_store_effectaddress_write, V, Ctx ⟶
ctx_fnCtx, Fn
loadV, l, si, Fn
insmov, q, regrsi, mem0, rax
1076rights_writeread, 0
1077rights_writewrite, 1

The effect list determines execution; only its caller publishes the result. No-aux jumps to lower_resolve's null arm. Resolving a box reads only its lower: address_read always reads the primary payload.

1082pointer_load_effects[], _, _, _ ⟶
[]
1083pointer_load_effectsE|Es, I, B, Ctx ⟶
1086pointer_load_effectaux_read, Index, Block, Ctx ⟶
local_labelCtx, Block, Index, nolower, NoLower
insjz, none, symNoLower, insmov, q, regrax, regrsi, inssub, q, regrcx, regrsi, insmov, q, mem0, rdx, rsi, regrsi
1093pointer_load_effectlower_resolve, Index, Block, Ctx ⟶
local_labelCtx, Block, Index, nolower, NoLower
local_labelCtx, Block, Index, have, Have
instest, b, imm1, regsil, insjz, none, symHave, insand, q, imm-2, regrsi, insmov, q, mem8, rsi, regrsi, insjmp, none, symHave, labelNoLower, insxor, l, regesi, regesi, labelHave
1104pointer_load_effectaddress_read, _, _, _ ⟶
insmov, q, mem0, rax, regrax, insmov, q, regrsi, regrcx
raw_load+T, +K, +D, +Index, +Block, +Ctx//

a scalar load of type T at K into tmp(D). Pointer loads require their explicit effect list.

1110raw_loadl, K, D, _, _, Ctx ⟶
integer_loadl, K, D, Ctx
1111raw_loads, K, D, _, _, Ctx ⟶
integer_loads, K, D, Ctx
1112raw_loadd, K, D, _, _, Ctx ⟶
integer_loadd, K, D, Ctx
1113raw_loadsw, K, D, _, _, Ctx ⟶
integer_loadsw, K, D, Ctx
1114raw_loaduw, K, D, _, _, Ctx ⟶
integer_loaduw, K, D, Ctx
1115raw_loadsh, K, D, _, _, Ctx ⟶
integer_loadsh, K, D, Ctx
1116raw_loaduh, K, D, _, _, Ctx ⟶
integer_loaduh, K, D, Ctx
1117raw_loadsb, K, D, _, _, Ctx ⟶
integer_loadsb, K, D, Ctx
1118raw_loadub, K, D, _, _, Ctx ⟶
integer_loadub, K, D, Ctx
1120integer_loadT, K, D, Ctx ⟶
load_insnT, K, LoadInsn
LoadInsn
reg_slot_storerax, tmpD, Ctx
checked_pointer_store+V, +A, +Index, +Block, +Ctx//

a store of the pointer V at A with its check, for an instruction whose store is internal (setjmp's jmp_buf).

1128checked_pointer_storeV, A, Index, Block, Ctx ⟶
access_checkk8, 1, 8, Ctx
pointer_store_effectsEffects, V, A, Index, Block, Ctx

A pointer store may exit during ensure-aux. Reload both rooted inputs after the helpers, before writing the lower and then the address.

1136pointer_store_effects[], _, _, _, _, _ ⟶
[]
1137pointer_store_effectsE|Es, V, A, I, B, Ctx ⟶
pointer_store_effectE, V, A, I, B, Ctx
pointer_store_effectsEs, V, A, I, B, Ctx
1141pointer_store_effectaux_ensure, _, _, Index, Block, Ctx ⟶
local_labelCtx, Block, Index, haveaux, HaveAux
insjnz, none, symHaveAux
slot_reg_loadthread, rdi, Ctx
inslea, q, mem-16, rcx, regrsi, inscall, none, pltfilc_object_ensure_aux_ptr_outline, insmov, q, regrax, regrdx, labelHaveAux
reg_slot_storerdx, aux, Ctx
1151pointer_store_effectlower_barrier, V, _, Index, Block, Ctx ⟶
local_labelCtx, Block, Index, nobarrier, NoBarrier
lower_reg_loadV, rsi, Ctx
instest, q, regrsi, regrsi, insjz, none, symNoBarrier, insmov, q, gotpcrelfilc_current_marking_state, regrax, inscmp, l, imm0, mem0, rax, insje, none, symNoBarrier
slot_reg_loadthread, rdi, Ctx
inscall, none, pltfilc_store_barrier_for_lower_slow, labelNoBarrier
1162pointer_store_effectrooted_reload, V, A, _, _, Ctx ⟶
ctx_fnCtx, Fn
slot_reg_loadaux, rdx, Ctx
insmov, q, regrax, regr8, inssub, q, regrcx, regr8
lower_reg_loadV, rsi, Ctx
loadV, l, r9, Fn
1170pointer_store_effectlower_write, _, _, _, _, _ ⟶
insmov, q, regrsi, mem0, rdx, r8
1172pointer_store_effectaddress_write, _, _, _, _, _ ⟶
insmov, q, regr9, mem0, rax

Scalar stores have no aux or barrier effects.

1176raw_storeb, V, _, _, _, Ctx ⟶
integer_storeb, V, Ctx
1177raw_storeh, V, _, _, _, Ctx ⟶
integer_storeh, V, Ctx
1178raw_storew, V, _, _, _, Ctx ⟶
integer_storew, V, Ctx
1179raw_storel, V, _, _, _, Ctx ⟶
integer_storel, V, Ctx
1180raw_stores, V, _, _, _, Ctx ⟶
integer_stores, V, Ctx
1181raw_stored, V, _, _, _, Ctx ⟶
integer_stored, V, Ctx

The code of a store of the integer V of width W at %rax.

1184integer_storeW, V, Ctx ⟶
ctx_fnCtx, Fn
store_insnW, d, StoreInsn
loadV, ValueK, d, Fn
StoreInsn
width_value_class?W, ?K

an integer store of width W reads its value at class K.

width_value_class
1193bw
1194hw
1195ww
1196ll
1197ss
1198dd

A call through an already checked function, whose lower is in the aux slot. The fast entry if the signature matches the call site's, else the generic entry with every argument as an 8-byte word at thread+128+8i and its lower at thread+384+8i (docs/abi-findings.md).

1204indirect_callSig, Form, Words, result_, Channels, ArgsSize, Cells, GenericResult, Index, Block, Ctx ⟶
ctx_fnCtx, Fn
special_labelCtx, exc, Exc
local_labelCtx, Block, Index, generic, Generic
local_labelCtx, Block, Index, done, Done
local_labelCtx, Block, Index, retok, RetOk
fieldfunction_object, signature, rcx, FoSig
fieldfunction_object, generic_entry, rsi, FoGeneric
insmovabs, q, immSig, regrsi, inscmp, q, regrsi, FoSig, insjne, none, symGeneric
fast_callForm, Words, indirect, Ctx
fast_resultForm, Channels, Ctx
insjmp, none, symDone, labelGeneric
generic_call_argsCells, Fn, Ctx
slot_reg_loadthread, rdi, Ctx
slot_reg_loadaux, rsi, Ctx
insmov, l, immArgsSize, regedx, inscall, q, indFoGeneric, instest, b, imm1, regal, insjnz, none, symExc
generic_resultsGenericResult, RetOk, Ctx
labelDone

The generic result cells, after the product's required-size check.

1231generic_resultsreceive_generic0, [], _, _ ⟶
[]
1232generic_resultsreceive_genericNeed, Cell|Cells, RetOk, Ctx ⟶
slot_reg_loadthread, rsi, Ctx
rets_checkNeed, RetOk
generic_slot_copiesCell|Cells, Ctx

Arguments, the entry registers and the call itself, for the fast convention in form Form; Callee is direct(Symbol) or indirect (through the aux slot).

1240fast_callForm, Ts, Callee, Ctx ⟶
ctx_fnCtx, Fn
typed_locationsTs, Form, Ls, NS, _
typed_stack_argsTs, Ls, Fn, Ctx
typed_register_argsTs, Ls, Fn, Ctx
entry_callForm, Callee, Pop, Ctx

The entry registers and the call of the fast entry of Callee. Pop is the stack words' size, which a buffered return's buffer sits above.

1251entry_callreg, directTarget, _, Ctx ⟶
slot_reg_loadthread, rdi, Ctx
insxor, l, regesi, regesi, inscall, none, Target
1255entry_callreg, indirect, _, Ctx ⟶
slot_reg_loadthread, rdi, Ctx
slot_reg_loadaux, rsi, Ctx
fieldfunction_object, fast_entry, rsi, Fast
inscall, q, indFast
1260entry_callmem_, directTarget, Pop, Ctx ⟶
slot_reg_loadthread, rsi, Ctx
inslea, q, memPop, rsp, regrdi, insxor, l, regedx, regedx, inscall, none, Target
1265entry_callmem_, indirect, Pop, Ctx ⟶
slot_reg_loadthread, rsi, Ctx
slot_reg_loadaux, rdx, Ctx
fieldfunction_object, fast_entry, rdx, Fast
inslea, q, memPop, rsp, regrdi, inscall, q, indFast

has_exception, then the result slots from %rdx:%rcx or the buffer.

1273fast_resultreg, floatK, T, Ctx ⟶
special_labelCtx, exc, Exc
instest, b, imm1, regal, insjnz, none, symExc
from_xmmK, xmm0, a
reg_slot_storerax, T, Ctx
1277fast_resultreg, slotsSlots, Ctx ⟶
special_labelCtx, exc, Exc
instest, b, imm1, regal, insjnz, none, symExc
reg_slot_storesSlots, rdx, rcx, Ctx
1282fast_resultmem_, slotsSlots, Ctx ⟶
special_labelCtx, exc, Exc
inscmp, b, imm0, mem0, rsp, insjne, none, symExc
buffer_slot_copiesSlots, 8, Ctx

The store of each register into the matching slot.

1289reg_slot_stores[], _, _ ⟶
[]
1290reg_slot_storesSlot|Slots, Reg|Regs, Ctx ⟶
reg_slot_storeReg, Slot, Ctx
reg_slot_storesSlots, Regs, Ctx

The copy of each buffer word into its slot; Slots start at Off(%rsp).

1295buffer_slot_copies[], _, _ ⟶
[]
1296buffer_slot_copiesSlot|Slots, Off, Ctx ⟶
insmov, q, memOff, rsp, regrax
reg_slot_storerax, Slot, Ctx
Off1 is Off + 8
buffer_slot_copiesSlots, Off1, Ctx

A generic return's words, from the thread at %rsi, into the slots.

1303generic_slot_copies[], _ ⟶
[]
1304generic_slot_copiescellI, _, T, Lower|Cells, Ctx ⟶
generic_offsetsI, Off, LowerOff
insmov, q, memOff, rsi, regrax
reg_slot_storerax, T, Ctx
generic_lower_slot_copyLower, LowerOff, Ctx

For a p word at thread offset Off, its lower into lower(T).

1312generic_lower_slot_copylowerT, LowerOff, Ctx ⟶
insmov, q, memLowerOff, rsi, regrax
reg_slot_storerax, lowerT, Ctx
1315generic_lower_slot_copynone, _, _ ⟶
[]

The check that the generic return size in %rdx is at least Need, with a call of filc_cc_rets_check_failure if it is not.

1319rets_checkNeed, RetOk ⟶
inscmp, q, immNeed, regrdx, insjae, none, symRetOk, insmov, q, regrdx, regrdi, insmov, l, immNeed, regesi, insxor, l, regedx, regedx, inscall, none, pltfilc_cc_rets_check_failure, insud2, none, [], labelRetOk

The store of each argument into the thread's generic argument area. Invariant: Args are the arguments from argument I on.

1331generic_call_args[], _, _ ⟶
[]
1332generic_call_argscellI, K, V, LowerSource|Cells, Fn, Ctx ⟶
generic_offsetsI, Addr, Lower
loadV, K, a, Fn
flight_lower_loadLowerSource, Ctx
slot_reg_loadthread, rdx, Ctx
insmov, q, regrax, memAddr, rdx, insmov, q, regrcx, memLower, rdx
generic_call_argsCells, Fn, Ctx

With a flight pointer in %rax:%rcx, jump to Fail unless it points at a function object. Clobbers %rdx, %rsi and %rdi.

1343function_checkFail ⟶
aux_bitsspecial_type, TypeMask
aux_bitsfunction, Function
instest, q, regrcx, regrcx, insjz, none, symFail, insmov, q, mem-8, rcx, regrdx, insmovabs, q, immTypeMask, regrsi, insand, q, regrdx, regrsi, insmovabs, q, immFunction, regrdi, inscmp, q, regrdi, regrsi, insjne, none, symFail, insmovabs, q, immMask, regrsi, insand, q, regrsi, regrdx, inscmp, q, regrdx, regrax, insjne, none, symFail

The aux pointer of the object at lower %rcx into %rdx, setting ZF if it has none.

1362aux_of_lower ⟶
insmov, q, mem-8, rcx, regrdx, insmovabs, q, immMask, regrsi, insand, q, regrsi, regrdx

A word into register R, an amd64 register short name (a, d, c, r8...).

1370word_reg_loadaddrV, R, Fn, _ ⟶
loadV, l, R, Fn
1371word_reg_loadvalK, V, R, Fn, _ ⟶
loadV, K, R, Fn
1372word_reg_loadlowerV, R, _, Ctx ⟶
reg_nameR, l, RN
lower_reg_loadV, RN, Ctx

The fast convention as data. A signature is a list of words wf(Class, Source): one per w, l, s or d value and two (address, then lower, both l) per p. typed_locations/5 places each word: integer words in the form's registers, s and d in %xmm0-7, the rest in stack words stack(I) at 8I(%rsp) at the call. Entries, call sites, the generic entry, the variadic adapter and external thunks all read this one placement, so they agree by construction.

1383typed_locationsTs, Form, Ls, NS, NX ←
findallK, memberwfK, _, Ts, Ks
bank_locationsKs, Rs, Ls, NS, NX
stack_bytes+NS, -Bytes

NS stack words take Bytes, keeping %rsp 16-aligned at the call.

1388stack_bytesNS, Bytes ←
Bytes is NS + 1//2 × 16
1390reserve_stack0 ⟶
[]
1391reserve_stackN ⟶
N > 0
inssub, q, immN, regrsp
1393typed_incoming[], [], _ ⟶
[]
1394typed_incomingwfK, T|Ts, L|Ls, Ctx ⟶
incoming_wordL, K, T, Ctx
typed_incomingTs, Ls, Ctx

An integer register word goes straight to its slot; others via %rax.

1398incoming_wordregR, _, T, Ctx ⟶
!
reg_nameR, l, RN
reg_slot_storeRN, T, Ctx
1400incoming_wordL, K, T, Ctx ⟶
1401incoming_bitsregR, _ ⟶
reg_nameR, l, RN
insmov, q, regRN, regrax
1403incoming_bitsxregX, K ⟶
from_xmmK, X, a
1404incoming_bitsstackI, K ⟶
O is 16 + 8 × I
reg_namea, K, A
insmov, S, memO, rbp, regA
1408typed_stack_args[], [], _, _ ⟶
[]
1409typed_stack_argswf_, W|Ts, L|Ls, Fn, Ctx ⟶
L = stackI
O is 8 × I
→
word_reg_loadW, a, Fn, Ctx
insmov, q, regrax, memO, rsp
else
[]
typed_stack_argsTs, Ls, Fn, Ctx
1413typed_register_args[], [], _, _ ⟶
[]
1414typed_register_argswfK, W|Ts, L|Ls, Fn, Ctx ⟶
typed_register_argL, K, W, Fn, Ctx
typed_register_argsTs, Ls, Fn, Ctx
1416typed_register_argstack_, _, _, _, _ ⟶
[]
1417typed_register_argregR, _, W, Fn, Ctx ⟶
word_reg_loadW, R, Fn, Ctx
1418typed_register_argxregX, K, W, Fn, Ctx ⟶
word_reg_loadW, a, Fn, Ctx
to_xmmK, a, X

Adapter sources are operands (thread/snapshot/saved stack), not IR values. Load all stack words first, then registers; only RAX is scratch.

1423adapter_stack[], [], _ ⟶
[]
1424adapter_stackwfK, W|Ts, L|Ls, G ⟶
L = stackI
O is 8 × I
→
insmov, q, regrax, memO, rsp
else
[]
adapter_stackTs, Ls, G
1428adapter_registers[], [], _ ⟶
[]
1429adapter_registerswfK, W|Ts, L|Ls, G ⟶
1431adapter_registerstack_, _, _, _ ⟶
[]
1432adapter_registerregR, K, memO, B, _ ⟶
K ≢ s
!
reg_nameR, l, RN
insmov, q, memO, B, regRN
1435adapter_registerregR, K, W, G ⟶
reg_nameR, l, RN
insmov, q, regrax, regRN
1438adapter_registerxregX, K, W, G ⟶
to_xmmK, a, X
1439adapter_loadK, W, G ⟶
K ≡ s
→
insmov, l, regeax, regeax
else
[]

Physical operands for the already flattened adapter sources.

1444adapter_wordArea, wfK, Source, wfK, Operand ←
adapter_operandArea, Source, Operand
1446adapter_operandthread, Source, memOff, rbx ←
channel_offsetSource, Off
1447adapter_operandsnapshot, dataI, memOff, r12 ←
Off is 8 × I
1448adapter_operandsnapshot, auxI, snapshot_lowerOff ←
Off is 8 × I
1449adapter_operandsnapshot, snapshot, regr12
1450saved_operandsavedI, memOff, rbp ←
Off is -32−8 × I

thunk(+Product)//: the lowered weak thunk resolves its symbol through the getter and calls the fast entry when the supplied signature matches, else transports its generic cells and result channels. Every incoming word, integer or XMM, is saved below rbp before the getter can exit or clobber caller-saved registers; rbx holds the thread (r12 the return buffer) and -24(%rbp) the function object. Pointer authority stays rooted by the caller.

1460thunkthunkF, Sig, Ts, Cells, ArgsSize, Result, Need ⟶
abi_symbolentrySig, F, FI
abi_symbolgetter, F, Getter
atom_concat'.L', FI, G
atom_concatG, '.generic', Generic
atom_concatG, '.out', Out
atom_concatG, '.fail', Fail
atom_concatG, '.retok', RetOk
atom_concatG, '.exc', Exc
Result = adapter_resultReturn, Channel, _, Packet
target_formReturn, Form
packet_offsetsPacket, packetSrcs, _
typed_locationsTs, Form, Ls, NS, _
saved_wordsTs, 0, Saved
lengthTs, NW
Alloc is 8 + 8 × NW + 15//16 × 16
fieldfunction_object, generic_entry, rsi, GenericEntry
sectiontext, p2align4, hiddenFI, weakFI, typeFI, function, labelFI, inspush, q, regrbp, insmov, q, regrsp, regrbp, inspush, q, regrbx, inspush, q, regr12, inssub, q, immAlloc, regrsp
save_mixed_wordsTs, Ls, Saved
insxor, l, regesi, regesi, inscall, none, pltGetter, insmov, q, regrdx, regrcx
fieldfunction_object, signature, rcx, Signature
insmov, q, regrcx, mem-24, rbp, insmovabs, q, immSig, regrsi, inscmp, q, regrsi, Signature, insjne, none, symGeneric
adapter_stackSaved, Ls, G
adapter_registersSaved, Ls, G
insjmp, none, symOut, labelGeneric
insmov, q, regrbx, regrdi, insmov, q, mem-24, rbp, regrsi, insmov, l, immArgsSize, regedx, inscall, q, indGenericEntry, instest, b, imm1, regal
thunk_generic_returnForm, Channel, Need, Srcs, Out, RetOk, Exc
labelFail, insmov, q, regrax, regrdi, insmov, q, regrcx, regrsi, inscall, none, pltfilc_check_function_call_fail, insud2, none, [], labelOut, inslea, q, mem-16, rbp, regrsp, inspop, q, regr12, inspop, q, regrbx, inspop, q, regrbp, insret, none, [], sizeFI
1496saved_words[], _, []
1497saved_wordswfK, _|Ts, I, wfK, memO, rbp|Ss ←
O is -32−8 × I
I1 is I + 1
saved_wordsTs, I1, Ss
1499mixed_thunk_threadreg ⟶
insmov, q, regrdi, regrbx
1500mixed_thunk_threadmem_ ⟶
insmov, q, regrdi, regr12, insmov, q, regrsi, regrbx, insmov, q, regrsi, regrdi
1503save_mixed_words[], [], [] ⟶
[]
1504save_mixed_wordswfK, _|Ts, L|Ls, wf_, W|Ss ⟶
insmov, q, regrax, W
1506mixed_thunk_callreg ⟶
fieldfunction_object, fast_entry, rsi, Fast
insmov, q, regrbx, regrdi, insmov, q, mem-24, rbp, regrsi, inscall, q, indFast
1510mixed_thunk_callmem_ ⟶
fieldfunction_object, fast_entry, rdx, Fast
insmov, q, regr12, regrdi, insmov, q, regrbx, regrsi, insmov, q, mem-24, rbp, regrdx, inscall, q, indFast
1514saved_generic[] ⟶
[]
1515saved_genericcellI, _, Data, savedL|Cells ⟶
1518saved_genericcellI, K, Data, none|Cells ⟶
adapter_loadK, W, unused
insmov, q, regrax, memAO, rbx, insmov, q, imm0, memLO, rbx

Access checks: k(Size, Write, Align), with the pointer in %rax and its lower in %rcx, which the failure block passes on.

A jump to the kind's failure block unless the pointer may be accessed: lower not 0, lower =< ptr =< upper - Size, the object's flags permitting a write if Write is 1, and ptr 8-aligned if Align is 8.

1530access_checkkSize, Write, Align, Ctx ⟶
check_fail_labelCtx, kSize, Write, Align, Fail
instest, q, regrcx, regrcx, insjz, none, symFail, inscmp, q, regrcx, regrax, insjb, none, symFail, insmov, q, mem-16, rcx, regrdx, inssub, q, immSize, regrdx, insjb, none, symFail, inscmp, q, regrdx, regrax, insja, none, symFail
write_checkWrite, Fail
align_checkAlign, Fail

For a write (Write = 1), a check of the object's read-only flags.

1545write_check0, _ ⟶
[]
1546write_check1, Fail ⟶
instest, b, imm6, mem-2, rcx, insjnz, none, symFail

For Align = 8, a check that the pointer is 8-aligned.

1551align_check1, _ ⟶
[]
1552align_check8, Fail ⟶
instest, b, imm7, regal, insjnz, none, symFail

The labels of a check kind's failure block and origin.

1557check_fail_labelCtx, kSize, Write, Align, Label ←
ctx_nameCtx, Name
formatatomLabel, '.L~w..fail.~w.~w.~w', Name, Size, Write, Align
1561check_origin_labelName, kSize, Write, Align, Label ←
formatatomLabel, '.L~w..chk.~w.~w.~w', Name, Size, Write, Align

The distinct check kinds the function's accesses need.

1565access_check_kindsBlocks, Kinds ←
findallKind,
memberblock_, _, Insts, _, Blocks
memberInst, Insts
inst_check_kindInst, Kind
,
Kinds0
sortKinds0, Kinds
inst_check_kind+Inst, -Kind

Inst's access needs a check of Kind; fails if Inst does not access memory.

1576inst_check_kindfusedcheck_, Size, Rights, Align, _, kSize, Write, Align ←
rights_writeRights, Write
1578inst_check_kindfusedcheck_local_, _, Size, Rights, Align, _, kSize, Write, Align ←
rights_writeRights, Write
1580inst_check_kindabiActions, k8, 1, 8 ←
memberchkreturns_twice_, _, _, _, _, Actions

A failure block for each check kind, calling the runtime's reporter.

1584check_fail_blocks[], _ ⟶
[]
1585check_fail_blocksKind|Kinds, Ctx ⟶
check_fail_labelCtx, Kind, Fail
ctx_nameCtx, Name
check_origin_labelName, Kind, Origin
labelFail, insmov, q, regrax, regrdi, insmov, q, regrcx, regrsi, inslea, q, ripOrigin, regrdx, inscall, none, pltfilc_optimized_access_check_fail, insud2, none, []

Function objects: every function gets a getter, a generic entry and a function object, so its address can be taken; exported ones also get the FI alias and a global getter.

Generic-only public entry, with a private fast body. Promotion is the only exiting call before the body roots the hidden snapshot parameter.

1603variadic_objectName, Linkage, Adapter, Impl ⟶
abi_symbolfunction_object, Name, FO
abi_symbolgetter, Name, Getter
abi_symbolimpl0, Name, Generic
abi_symbolentry0, Name, FI
atom_concatGeneric, '.body', BodyObject
linkage_aliasLinkage, FI, Generic, Getter
object_getterGetter, FO
variadic_adapterGeneric, BodyObject, Adapter
sectiondata_rel_ro, p2align4, labelBodyObject, quadImpl
function_object_dataFO, 0, Generic, 0
1615variadic_adapterGeneric, BodyObject, promote_incomingNeed, Words, Result ⟶
Result = adapter_resultReturn, Channel, RetSize, Packet
target_formReturn, Form
packet_offsetsPacket, PlacedPacket
maplistadapter_wordsnapshot, Words, Ts
typed_locationsTs, Form, Ls, NS, _
atom_concatGeneric, '.short', Short
atom_concatGeneric, '.done', Done
sectiontext, typeGeneric, function, labelGeneric, inspush, q, regrbx, inspush, q, regr12, inspush, q, regr13, inscmp, q, immNeed, regrdx, insjb, none, symShort, insmov, q, regrdi, regrbx, insmov, q, regrdx, regrsi, inscall, none, pltfilc_promote_args_to_heap, insmov, q, regrax, regr12, insxor, l, regr13d, regr13d, instest, q, regrdx, regrdx
atom_concatGeneric, '.aux', Aux
insjz, none, symAux, insmov, q, mem-8, rdx, regr13, insmovabs, q, immMask, regrax, insand, q, regrax, regr13, labelAux
adapter_stackTs, Ls, Generic
adapter_registersTs, Ls, Generic
insmov, q, regrbx, regrdi, inslea, q, ripBodyObject, regrsi
generic_entry_callForm, Channel, PlacedPacket, Pop, RetSize, Done
inspop, q, regr13, inspop, q, regr12, inspop, q, regrbx, insret, none, [], labelShort, insmov, q, regrdx, regrdi, insmov, l, immNeed, regesi, insxor, l, regedx, regedx, inscall, none, pltfilc_cc_args_check_failure, insud2, none, []
1655snapshot_loadregR, _ ⟶
insmov, q, regR, regrax
1656snapshot_loadmemO, R, _ ⟶
insmov, q, memO, R, regrax
1657snapshot_loadsnapshot_lowerO, G ⟶
formatatomNoAux, '~w.lower.~w', G, O
insxor, l, regeax, regeax, instest, q, regr13, regr13, insjz, none, symNoAux, insmov, q, memO, r13, regrax, labelNoAux
1664function_objectName, Linkage, Adapter, Sig, Impl ⟶
abi_symbolentrySig, Name, FI
abi_symbolfunction_object, Name, FO
abi_symbolgetter, Name, Getter
formatatomGeneric, '.L~w..generic', Name
linkage_aliasLinkage, FI, Impl, Getter
object_getterGetter, FO
generic_entryGeneric, Adapter
sectiondata_rel_ro, p2align4
function_object_dataFO, Impl, Generic, Sig

The getter of a function object FO: its flight pointer, whose lower is its address, in %rax:%rdx.

1677object_getterGetter, FO ⟶
typeGetter, function, labelGetter, inslea, q, ripFO + 16, regrax, insmov, q, regrax, regrdx, insret, none, []

The function object FO with the entries Fast and Generic (symbols, or 0 for none) and signature Sig. Its header has upper = lower, so it cannot be read or written, and an aux word that points at itself.

1686function_object_dataFO, Fast, Generic, Sig ⟶
aux_bitsglobal, readonly, function, Flags
typeFO, object, labelFO, quadFO + 16, quadFO + 16 + Flags, quadFast, quadGeneric, quadSig, sizeFO, 40

An exported function's FI alias of Impl and its global Getter.

1697linkage_aliasexport, FI, Impl, Getter ⟶
globlFI, typeFI, function, setFI, Impl, globlGetter
1699linkage_aliaslocal, _, _, _ ⟶
[]

The .globl of S if its linkage is export.

1702linkage_globlexport, S ⟶
globlS
1703linkage_globllocal, _ ⟶
[]

Data objects, as clang lays out globals (docs/abi-findings.md): DO_d = {upper, aux} then the payload rounded up to 8 bytes, a 16-byte cache GP_d, an aux array DA_d if the payload holds pointers, and a getter whose slow path registers the object and runs the relocations that fill in its pointers.

1711data_objectName, Linkage0, Items ⟶
linkage_flagsLinkage0, Linkage, Flags
abi_symboldata_object, Name, DO
abi_symboldata_aux, Name, DA
formatatomGP, '.LpizlonatedGP_~w', Name
abi_symbolgetter, Name, Getter
formatatomRelocs, '.Lpizlonated_~w..relocs', Name
formatatomSlow, '.Lpizlonated_~w..slow', Name
formatatomInited, '.Lpizlonated_~w..inited', Name
foldlpayload_item, Items, Payload, 0−[], Size0−Rs0
reverseRs0, Rs
Size is Size0 + 7//8 × 8
Pad is Size−Size0
relocs_aux_wordRs, Flags, DA, AuxWord
Total is 16 + Size
sectiondata, p2align4, typeDO, object, labelDO, quadDO + 16 + Size, quadAuxWord
seqPayload
Pad > 0
→
zeroPad
else
[]
sizeDO, Total
sectionbss, p2align4, labelGP, zero16
aux_arrayRs, DA, Size, Relocs, Name
sectiontext, p2align4
linkage_globlLinkage, Getter
typeGetter, function, labelGetter, insmov, q, ripGP, regrax, insmov, q, ripGP + 8, regrdx, instest, q, regrax, regrax, insjz, none, symSlow, instest, q, regrdx, regrdx, insjz, none, symSlow, insret, none, [], labelSlow, inspush, q, regrbx, insmov, q, regrdi, regrbx, inslea, q, ripGP, regrdx, inslea, q, ripDO, regrcx, inscall, none, pltfilc_global_initialization_start, instest, b, imm1, regal, insjz, none, symInited
relocations_callRs, DO, Relocs
insmov, q, regrbx, regrdi, inscall, none, pltfilc_global_initialization_end, labelInited, inspop, q, regrbx, inslea, q, ripDO + 16, regrax, insmov, q, regrax, regrdx, insret, none, []
relocs_aux_word+Rs, +Flags, +DA, -AuxWord

AuxWord is the aux word of a global data object with relocations Rs and other flags Flags: its flags, and its static aux array DA if it holds pointers.

1766relocs_aux_word[], Flags, _, Bits ←
aux_bitsglobal|Flags, Bits
1768relocs_aux_word_|_, Flags, DA, DA + Bits ←
aux_bitsglobal, global_aux|Flags, Bits

The aux array DA of Size bytes and the relocation table Relocs, if there are relocations Rs.

1773aux_array[], _, _, _, _ ⟶
[]
1774aux_arrayR|Rs, DA, Size, Relocs, Name ⟶
p2align4, labelDA, zeroSize
sectiondata_rel_ro, p2align4, labelRelocs
relocationsR|Rs, Name

The getter's call that runs the relocations Rs, if there are any, of data object DO from the table Relocs.

1781relocations_call[], _, _ ⟶
[]
1782relocations_callR|Rs, DO, Relocs ⟶
lengthR|Rs, NRelocs
insmov, q, regrbx, regrdi, inslea, q, ripDO, regrsi, inslea, q, ripRelocs, regrdx, insmov, l, immNRelocs, regecx, inscall, none, pltfilc_execute_constant_relocations
linkage_flags+Linkage0, -Linkage, -Flags

a data object of linkage Linkage0 has linkage Linkage and, if read-only, the flag readonly.

linkage_flags
1792roLinkageLinkagereadonly
1793exportexport[]
1794locallocal[]
payload_item+Item, -Line, +Off0−Rs0, −Off−Rs

Line is the payload directive of Item at offset Off0, and Rs adds to Rs0 a relocation r(Offset, Symbol, Addend) if Item is a pointer, whose slot stays 0 until the relocation fills it in. Off is the offset after Item.

1800payload_itemzeroN, zeroN, Off0−Rs, Off−Rs ←
Off is Off0 + N
1802payload_itemitemW, Value, Line, S0, S ←
value_payloadValue, W, Line, S0, S
value_payload+Value, +W, -Line, +Off0−Rs0, −Off−Rs

as payload_item/4 for item(W, Value).

1807value_payloadstrCs, b, asciiCs, Off0−Rs, Off−Rs ←
lengthCs, N
Off is Off0 + N
1810value_payloadsymS, Addend, p, quad0, Off0−Rs, Off−rOff0, S, Addend|Rs ←
Off0 mod 8 =:= 0
→
true
else
thrownanofil_error'pointer data item is not 8-aligned'
Off is Off0 + 8
1817value_payloadconstN, W, Directive, Off0−Rs, Off−Rs ←
width_bytesW, Bytes
Bits is 8 × Bytes
U is N mod 1 << Bits
memberchkBytes−Directive, 1−byteU, 2−shortU, 4−longU, 8−quadU
Off is Off0 + Bytes

Each relocation is {u64 offset, u32 kind, pad, target}: kind 0 calls a getter, kind 1 a constexpr node {u32 add-immediate = 0, u32 0, getter, u64 addend}.

1828relocationsRs, Name ⟶
reloc_entriesRs, 0, Name
reloc_nodesRs, 0, Name

The relocation table. Invariant: Rs are the relocations from the Ith.

1833reloc_entries[], _, _ ⟶
[]
1834reloc_entriesrOff, S, Addend|Rs, I, Name ⟶
abi_symbolgetter, S, Getter
Addend =:= 0
→
quadOff, long0, zero4, quadGetter
else
reloc_nodeName, I, Node
quadOff, long1, zero4, quadNode
I1 is I + 1
reloc_entriesRs, I1, Name

The constexpr node of each relocation with an addend. Invariant: Rs are the relocations from the Ith.

1846reloc_nodes[], _, _ ⟶
[]
1847reloc_nodesr_, S, Addend|Rs, I, Name ⟶
Addend =:= 0
→
[]
else
abi_symbolgetter, S, Getter
reloc_nodeName, I, Node
U is Addend mod 18446744073709551616
labelNode, long0, long0, quadGetter, quadU
I1 is I + 1
reloc_nodesRs, I1, Name
reloc_node+Name, +I, -Node

Node labels the constexpr node of relocation I of data object Name.

1860reloc_nodeName, I, Node ←
formatatomNode, '.Lpizlonated_~w..node~w', Name, I
thunk_generic_return+Form, +RetKs, +Need, +GWs, +Out, +RetOk, +GenericExc//

the return, in form Form, of the generic entry's result words GWs, of classes RetKs and Need bytes, then a jump to Out.

1866thunk_generic_returnreg, RetKs, Need, GWs, Out, RetOk, _ ⟶
insjnz, none, symOut
thunk_generic_reg_wordsRetKs, Need, GWs, RetOk
insxor, l, regeax, regeax, insjmp, none, symOut
1871thunk_generic_returnmem_, _, Need, Srcs, Out, RetOk, GenericExc ⟶
insjnz, none, symGenericExc
rets_checkNeed, RetOk
insmov, b, imm0, mem0, r12, insmov, q, regr12, regrax, insjmp, none, symOut, labelGenericExc, insmov, b, imm1, mem0, r12, insmov, q, regr12, regrax, insjmp, none, symOut

The result words, if RetKs has any, in %rdx:%rcx.

1884thunk_generic_reg_wordsvoid, _, _, _ ⟶
[]
1885thunk_generic_reg_wordsfloatK, Need, Off, RetOk ⟶
rets_checkNeed, RetOk
insmov, S, memOff, rbx, regR
to_xmmK, d, xmm0
1889thunk_generic_reg_wordswords, Need, Srcs, RetOk ⟶
rets_checkNeed, RetOk
thunk_reg_loadsSrcs, rdx, rcx

The load of each generic return word, at thread offset Off, into its register.

1895thunk_reg_loads[], _ ⟶
[]
1896thunk_reg_loadsOff|Offs, Reg|Regs ⟶
insmov, q, memOff, rbx, regReg
thunk_reg_loadsOffs, Regs

The copy of each generic return word, at thread offset Src, into the return buffer at Off(%r12).

1902thunk_buffer_copies[], _ ⟶
[]
1903thunk_buffer_copiesSrc|Srcs, Off ⟶
insmov, q, memSrc, rbx, regrax, insmov, q, regrax, memOff, r12
Off1 is Off + 8

The operand Word into the thread at offset Off, through %rax if it is in memory.

1911operand_thread_storeregR, Off ⟶
insmov, q, regR, memOff, rbx
1913operand_thread_storememD, B, Off ⟶
insmov, q, memD, B, regrax, insmov, q, regrax, memOff, rbx

The generic entry: {i1, i64 ret_size} (thread, callee_lower, args_size). Argument i is 8 bytes at thread+128+8i, with its lower (for p) at thread+384+8i, and so is result word i. It calls the fast entry through callee_lower, with a buffer on the stack for a buffered return.

1922generic_entryGeneric, adaptNeed, Words, Result ⟶
Result = adapter_resultReturn, Channel, RetSize, Packet
target_formReturn, Form
packet_offsetsPacket, PlacedPacket
maplistadapter_wordthread, Words, Ts
typed_locationsTs, Form, Ls, NS, _
atom_concatGeneric, '.short', Short
atom_concatGeneric, '.done', Done
sectiontext, labelGeneric, inspush, q, regrbx, inscmp, q, immNeed, regrdx, insjb, none, symShort, insmov, q, regrdi, regrbx
adapter_stackTs, Ls, Generic
adapter_registersTs, Ls, Generic
generic_entry_callForm, Channel, PlacedPacket, Pop, RetSize, Done
inspop, q, regrbx, insret, none, [], labelShort, insmov, q, regrdx, regrdi, insmov, l, immNeed, regesi, insxor, l, regedx, regedx, inscall, none, pltfilc_cc_args_check_failure, insud2, none, []

generic_entry_call(+Form, +Channel, +Packet, +Pop, +RetSize, +Done)//: call the fast entry in placed Form, then transport Channel into the placed Packet and return RetSize in %edx. Pop is the native stack argument size. Exceptions skip all result reads and size production.

1942generic_entry_callreg, Channel, Packet, Pop, RetSize, Done ⟶
fieldfunction_object, fast_entry, rsi, Fast
inscall, q, indFast
instest, b, imm1, regal, insjnz, none, symDone
generic_reg_resultsChannel, Packet
insmov, l, immRetSize, regedx, labelDone
1951generic_entry_callmemBytes, _, packetDests, Zeros, Pop, RetSize, Done ⟶
fieldfunction_object, fast_entry, rdx, Fast
insmov, q, regrsi, regrdx, insmov, q, regrbx, regrsi, inslea, q, memPop, rsp, regrdi, inscall, q, indFast
insmov, b, mem0, rsp, regal, instest, b, regal, regal, insjnz, none, symDone
insmov, l, immRetSize, regedx, insxor, l, regeax, regeax, labelDone

The result words from %rdx:%rcx at their thread offsets; a void result is one zero word.

1970generic_reg_resultsvoid, packet[], Zeros ⟶
1971generic_reg_resultsfloatK, packetOff, Lower ⟶
from_xmmK, xmm0, d
insmov, q, regrdx, memOff, rbx, insmov, q, imm0, memLower, rbx
1975generic_reg_resultswords, packetDests, Zeros ⟶

The store of each result register at its thread offset.

1980generic_reg_stores[], _ ⟶
[]
1981generic_reg_storesOff|Offs, Reg|Regs ⟶
insmov, q, regReg, memOff, rbx

The copy of each return buffer word, from Off(%rsp) on, to thread offset Dest.

1987generic_buffer_copies[], _ ⟶
[]
1988generic_buffer_copiesDest|Dests, Off ⟶
insmov, q, memOff, rsp, regrax, insmov, q, regrax, memDest, rbx
Off1 is Off + 8

Explicit zero channels from the ABI product.

1995generic_zeroings[] ⟶
[]
1996generic_zeroingsOff|Offs ⟶
insmov, q, imm0, memOff, rbx

Static data: function origins (staging's 48-byte layout), origins, and one access-check origin per check kind.

The name string, the c and n function origins with their origins, and the check origins of function Name.

2004originsName, Origins, CheckKinds ⟶
formatatomNameLabel, '.L~w..name', Name
sectionrodata, labelNameLabel, ascizName, sectiondata_rel_ro, p2align4
function_originsOrigins, Name, NameLabel
check_originsCheckKinds, Name
2011function_origins[], _, _ ⟶
[]
2012function_originsoriginWhich, Catch, NLowers, NumSetjmps, NumLocals|Origins, Name, NameLabel ⟶
catch_flagCatch, CanCatch
function_originName, NameLabel, NLowers, Which, CanCatch, NumSetjmps, NumLocals
function_originsOrigins, Name, NameLabel
2016catch_flagcatches, 1
2017catch_flagno_catch, 0

A function origin and the origin (origin_label/3) that points at it.

2020function_originName, NameLabel, NLowers, Which, CanCatch, NumSetjmps, NumLocals ⟶
formatatomFOrigin, '.L~w..forigin_~w', Name, Which
origin_labelName, Which, Origin
labelFOrigin, quadNameLabel, quad0, longNLowers, zero4, quad0, byte0, CanCatch, zero2, longNumSetjmps, longNumLocals, zero4, labelOrigin, quadFOrigin, long0, long0

An access-check origin for each check kind.

2033check_origins[], _ ⟶
[]
2034check_originsKind|Kinds, Name ⟶
Kind = kSize, Write, Align
check_origin_labelName, Kind, Label
origin_labelName, n, Origin
p2align4, labelLabel, longSize, byteAlign, 0, Write, zero1, quadOrigin, quadOrigin, quad0
check_originsKinds, Name