Fil-C on Nix

Filnix wiki

mbrock/filnix/nanofil

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.pl168 lines · 34 clausesAddress 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.pl851 lines · 260 clausesThe 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.pl231 lines · 153 clausesAudited 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. amd64_regs.pl1120 lines · 192 clausesWhole-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.pl1396 lines · 542 clausesTranslation 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.pl231 lines · 71 clausesx86-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.pl833 lines · 307 clausesThe C lexer (milestone 4a): it turns preprocessed C text into a list of tokens, each with its file and line.c_lower.pl6689 lines · 1104 clausesLowering 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.pl1523 lines · 306 clausesThe C parser (milestone 4a): it turns the tokens from c_lex into a syntax tree.c_pp.pl1076 lines · 236 clausesThe 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.pl5828 lines · 1324 clausesC'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.pl600 lines · 83 clausesControl-flow analyses over one function's blocks, as pure functions from IR terms to assocs keyed by block label.cfg_tabled.pl306 lines · 23 clausesThe 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.pl1197 lines · 196 clausesCheck 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.pl295 lines · 56 clausesShared 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.pl330 lines · 52 clausesCopy 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.pl284 lines · 54 clausesEscape 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.pl511 lines · 120 clausesFil-C ABI lowering, before AMD64 placement and instruction selection.filc_amd64.pl3741 lines · 748 clausesThe 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.pl262 lines · 50 clausesConservative 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.pl149 lines · 18 clausesHalf checks: a check whose object was checked before at another range tests only the bound that is not already known (docs/half.md).ieee.pl267 lines · 61 clausesIEEE 754 binary32 and binary64 arithmetic with integers only, rounding to nearest, ties to even.inline.pl708 lines · 127 clausesInlining 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.pl1833 lines · 449 clausesRelational 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.pl2860 lines · 682 clausesThe 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.pl145 lines · 41 clausesIR 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.pl430 lines · 73 clausesPointer-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.pl17 lines · 2 clausesStable 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.pl135 lines · 15 clausesNonescaping memory that remains after scalar promotion.lower_roots.pl161 lines · 22 clausesShared 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.pl242 lines · 32 clausesThe 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.pl1225 lines · 171 clausesThe 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.pl1009 lines · 398 clausesNFB, 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.pl155 lines · 31 clausesThe middle end's entry points for the driver, and the comparison the interpreter uses to validate it.pizlonate.pl268 lines · 41 clausesPizlonation: 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.pl902 lines · 129 clausesPromotion 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.pl369 lines · 82 clausesExplanatory context, separate from executable IR and safety evidence.schedule.pl254 lines · 59 clausesScheduled 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.pl795 lines · 192 clausesA 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`.