Fil-C on Nix

Filnix wiki

mbrock/filnix/nanofil

opt.pl

The middle end's entry points for the driver, and the comparison the interpreter uses to validate it.

optimize/3 runs the passes at a level, or an explicit ordered subset:

o0:  M0 ─────────────────────────────────────▶ M
o1:  M0 ─▶ promote ─▶ copy ─▶ local_storage ─▶ M

optimization_passes/2 names that sequence. optimize_pass/3 runs one member, so the playground can time it and show its actual output without implementing another optimizer. passespromote, copy, for example, leaves local storage off. Ordering stays fixed: local storage introduces a vocabulary the earlier passes do not consume.

refines/2 relates the outcome of a program to the outcome of its optimized version. The driver's difftest and the unit tests validate the optimized IR, rather than repeating that work on every compilation. These passes consume unchecked IR only. A checked module supplied directly (even with -O) is left unchanged: promotion and substitution do not understand proofs or flight projections.

usescopy
usesirmodule_stage/2, local_objects/2
useslists
optimize+Options, +M0, -Msemidet

Options is o0 (the reference path), o1 (all three passes), or passes(Names), an ordered subset of o1. Invalid selections fail. Checked or already-local IR stays unchanged.

38optimizeOptions, M0, M ←
optimization_passesOptions, Passes
foldloptimize_pass, Passes, M0, M
optimization_passes+Options, -Passessemidet

Passes is the selected sequence. A selection can omit passes but cannot reorder or repeat them, or name an unknown pass.

46optimization_passeso0, []
47optimization_passeso1, promote, copy, local_storage
48optimization_passespassesPasses, Passes ←
52ordered_passes[], _
53ordered_passesP|Ps, All ←
append_, P|Rest, All
optimize_pass+Name, +M0, -Msemidet

Run one named transformation on unchecked, ordinary-address IR. Each pass transports its source contexts alongside executable IR. Unknown names fail; all guards remain in the existing pass modules.

62optimize_passName, M0, M ←
pass_predicateName, Goal
→
M = M0
else
callGoal, M0, M
pass_predicate
69promotepromote_module
70copycopy_module
71local_storagelocal_storage_module

Named local objects are already the storage pass's product. Earlier passes consume ordinary addresses, not this lowered vocabulary.

75has_local_storagemoduleItems ←
memberF, Items
F = func_, _, _, _, _
refines+Before, +Aftersemidet

After is an outcome the original program allows, given that the original's outcome was Before, both from interp:run/5 on the same inputs:

- undefined behaviour allows anything;
- an unknown result (read of uninitialized bytes in plain mode)
  allows any value consistent with its constraints;
- otherwise the outcomes must be equal. A pointer into an alloc
  compares by its offset in the object, because removing allocs
  moves the ones left; data and function addresses do not move.
92refinesub_, _ ←
!
93refinesBefore0, After0 ←
outcome_keyBefore0, Before
outcome_keyAfter0, After
groundBefore
→
Before ≡ After
else
¬¬Before = After
outcome_key+Outcome, -Key

Key is Outcome, except that a returned pointer into an alloc is keyed by its offset in the object.

103outcome_keyretP, retobj_ptrOff ←
nonvarP
P = ptrAddr, objBase
integerAddr
!
Off is Addr−Base
109outcome_keyOutcome, Outcome