nanofil, read as Prolog
nanofil is a C compiler written in Prolog that emits Fil-C ABI assembly. It aims to read like the standards it implements: each fact about C, the IR or Fil-C stated once, as a relation everything else reads (the campaign). These pages draw its source as terms: clause heads over their goals, conditionals as tables, fact tables as tables, PlDoc as signatures. The guide's module map says what each module is for, and the workbench how terms are set.
alias.plAddress expressions for milestone 5: alias_facts/2 writes each address of a strict SSA function as a base plus a constant offset. The facts are not a no-alias or bounds proof.amd64.plThe naive x86-64 SysV backend for the phase-one IR in plain (non-Fil-C) mode (milestone 2). It is the reference the later instruction selection and register allocation milestones are checked against, so it favours being obviously right over being fast.amd64_contract.plAudited machine forms for the scalar stack cache. Unknown forms fail, selecting the unchanged implementation, rather than guessing effects. Reads name register families. write(Family,Bits) records partial writes: 32 bits zero-extend, 8/16 preserve the rest. Memory effects include addressing-register reads; flags and control/frame effects are separate. This describes selected instructions, not IR liveness or GC roots. Calls are unconditional cache boundaries; their ABI argument reads are not enumerated. Do not use this as a general call-liveness contract. Three compiler-local save stubs additionally preserve r10/r11 on normal return (docs/abi-findings.md); their original PLT calls do not. amd64_regs.plWhole-function register homes for scalar temporaries (docs/perf.md item 3, step 3a), with step 3b's operand rewrite and 5a-loads' frame cells: `--registers=temps`, and `--registers=pointers`, the -O default. A fixed map puts frame homes in registers for the whole function: homes live across a call in the callee-saved rbx and r12-r15, the others also in r10/r11. Accesses stay the moves the reference emits, with a register in place of the slot; no instruction is selected differently.amd64_regs_check.plTranslation validation for whole-function scalar register homes (docs/perf.md item 3, run by `--registers=temps`). The allocator proposes a fixed map from frame homes to registers; nothing about how it chose the map is trusted here.asm.plx86-64 assembly as terms, and their printer as GNU as (AT&T) text. The backends build a list of lines; this module is the only place that knows AT&T syntax.c_lex.plThe C lexer (milestone 4a): it turns preprocessed C text into a list of tokens, each with its file and line.c_lower.plLowering from C to IR (milestone 4b), in the style of cproc: it turns the parsed translation unit into an IR module for the Fil-C backend.c_parse.plThe C parser (milestone 4a): it turns the tokens from c_lex into a syntax tree.c_pp.plThe C preprocessor (milestone 4e): it expands a C file's macros, includes and conditionals and hands the result to c_lex as tokens.c_types.plC's types as terms: specifiers and declarators become type terms, and from those come sizes and layouts, the integer conversions and the values of constant expressions (milestone 4a).cfg.plControl-flow analyses over one function's blocks, as pure functions from IR terms to assocs keyed by block label.cfg_tabled.plThe analyses of cfg.pl as tabled relations over IR facts, in the two styles the handoff proposed. They exist to answer PLAN's open question by measurement (tests/bench-cfg.pl, docs/m5.md); passes use cfg.pl.check_reuse.plCheck reuse: a heap access check's proof covers later scalar accesses through the same pointer or a related one, in its block and along CFG edges (docs/m7.md).check_share.plShared check parts: a heap check of an object an earlier check already tested skips the null test, and right after a check of the same object reuses the upper it loaded (docs/perf.md item 17).copy.plCopy propagation, run after promote: copy_module/2 removes copies and trivial phis from each function in strict SSA form, replacing every use by the value it copies.escape.plEscape 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.filc_abi.plFil-C ABI lowering, before AMD64 placement and instruction selection.filc_amd64.plThe 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.frame_slots.plConservative 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.half_check.plHalf checks: a check whose object was checked before at another range tests only the bound that is not already known (docs/half.md).ieee.plIEEE 754 binary32 and binary64 arithmetic with integers only, rounding to nearest, ties to even.inline.plInlining of static functions on unchecked IR before promotion: `--inline=small` (docs/perf.md item 4) takes small leaves in two rounds; `--inline=wide` (item 20) goes callees first through the call graph and takes non-leaf callees, callees with one call site, and always_inline ones.interp.plRelational semantics of the IR (ir.pl): the outcome of running a function of a module, as a relation that runs in every direction, so that arguments and outcome can both be partially unknown.ir.plThe nanofil IR: modules of functions and data as ground Prolog terms, the contract between the frontend, the middle end, the interpreter and the backends. This module states its grammar and checks that a module is well formed.ir_text.plIR text: a module written as Prolog clauses, one func/5 or data/4 term (ir.pl) per item in module order, and read back with read_term/3.launder.plPointer-as-integer laundering: an integer converted back to a pointer (`itop`) keeps the capability of the one pointer it was computed from, by launder_module/2. Fil-C's FilPizlonator does this with `inferPointerAsIntLaunderingForFunction`; this pass states the same abstract interpretation on nanofil's IR, before any optimization, so that the result does not depend on `-O`.list_partition.plStable list partitioning shared by promotion and register selection. Trealla's library(lists) supplies include/3 and exclude/3, but not SWI's partition/4. Evaluate the predicate only once per element. local_storage.plNonescaping memory that remains after scalar promotion.lower_roots.plShared lowers: a derived pointer's `lowers[]` entry is its lower root's (docs/lowers.md). Opt-in as `--lowers=shared`; the default, own, gives every pointer temporary an entry of its own.lowers_check.plThe GC-root contract of a frame, checked: at every point of every reachable block, each live pointer temporary's `lowers[]` entry holds its current lower (docs/lowers.md). The collector marks the object of every lower in the frame record at each safepoint, so a live pointer whose entry held anything else could lose its object.main.plThe nanofil command line: the impure driver that reads a C or IR file, runs it through the compiler's stages and prints the result.nfb.plNFB, the nanofil bytecode: a module of ir.pl written as little-endian 32-bit words in a sectioned container, and read back (docs/nfb.md). The encoding is a function of the module, and the reader accepts only its image, so the words are the module's identity.opt.plThe middle end's entry points for the driver, and the comparison the interpreter uses to validate it.pizlonate.plPizlonation: from the unchecked IR to the checked IR (ir.pl), the form the Fil-C backend compiles, named after Fil-C's LLVM pass.promote.plPromotion of memory slots to SSA temporaries, by promote_module/2 and promote_func/3. Prior art: QBE's promote and ssa passes, LLVM's mem2reg.provenance.plExplanatory context, separate from executable IR and safety evidence.schedule.plScheduled checks (docs/schedule.md): a check of a struct pointer covers, early, the bytes that every path ahead of it will need, so that the later checks of the same object become renewals.simplify.plA cheap middle end (docs/perf.md item 8), run after copy propagation on unchecked IR in strict SSA form: simplify_module/2 folds constants, simplifies booleans and identities, numbers pure values, folds constant branches, removes unreachable blocks and dead pure definitions, and merges straight-line blocks. Selected with `--simplify=full`.