Fil-C on Nix

Filnix wiki

the formal campaign

rocq/theories/Syntax.v

The core subset of the checked IR, transcribed from ir.pl: its grammar as inductive types, one constructor per functor of the intermediate representation (IR), and the small tables of facts the semantics reads.

The subset is formal.md's: filc mode, the checked stage, the integer and pointer classes, check and its reuse vocabulary, the raw_* accesses, flight, poll edges, call, raw_call and free, and named locals; and, for the Lua suite, the float classes with their conversions (Ieee.v) and variadic functions (va_args, va_arg). Vectors, cas and atomics, setjmp, asm_fixed and plain mode are deferred: a function that uses them is IOutside, which has an address but no body (Transport.v decides).

Items, blocks and instructions

Gallinair.pl
IFuncffunc(Name, Linkage, Ret, Params, Blocks)
IOutsiden ta func named n outside the core subset, kept as its term t
IDatan lk al itemsdata(Name, Linkage, Align, Items)
IAliasn lk talias(Name, Linkage, Target)
Phid k pairsphi(tmp(D), K, [Pred-Value])
Letd k o argslet(tmp(D), K, Op, Args)
Flightd o args lowerflight(tmp(D), Op, Args, Lower)
RawStorew off v araw_store(Width, Off, Value, Addr)
RawStorePointeroff v a esraw_store_pointer(Off, Value, Addr, Effects)
Callr callee argscall(Res, Callee, [arg(K, Value)])
RawCallr callee argsraw_call(Res, Callee, Args)
LocalAllocx sizelocal_alloc(Name, Size)
Locfile lineloc(File, Line)
From Stdlib Require Import String ZArith List Bool
From Nanofil Require Import Term
Import ListNotations
Open Scope Z_scope

Classes and widths

As class(K, Kind, Bits): the class of a value, one letter in ir.pl. Besides the integer, pointer and float classes there are the two proof classes of the checked stage, whose values are pointers a check has cleared.

Classir.plValue
Wwa 32-bit integer
Lla 64-bit integer
Ppa pointer: an address with its capability
Aaa proven address, the result of a check
Ffa proven function, the result of check_function
Singlesan IEEE binary32 float, held as its 32-bit pattern
Doubledan IEEE binary64 float, held as its 64-bit pattern
Extendedxan x87 extended float, held as its 80-bit pattern

Extended is C's longdouble, never a parameter, result, call argument or phi.

59Inductive class: Type ≔
|W
|L
|P
|A
|F
|Single
|Double
|Extended

Equality of classes.

62Definition class_eqbk k′ : class : bool ≔
match k, k′ with
W, W | L, L | P, P | A, A | F, F | Single, Single | Double, Double | Extended, Extended
⇒
true
_, _
⇒
false

As float_class(K): whether the class k is a float class, s, d or x.

71Definition float_classk : class : bool ≔
match k with
_
⇒
false

As int_class(K): whether the class k is an integer class, w or l.

76Definition int_classk : class : bool ≔
match k with
W | L
⇒
true
_
⇒
false

As modulus(K, Mod): the values of class k are the integers from 0 up to Mod - 1, a float's being its bit pattern; a P value's address has the modulus of L. The proof classes have none.

82Definition modulusk : class : optionZ ≔
match k with
⇒
Some2 ^ 32
L | P | Double
⇒
Some2 ^ 64
⇒
Some2 ^ 80
A | F
⇒
None

As class_bits(K, Bits): the width in bits of an integer class k.

92Definition class_bitsk : class : optionZ ≔
match k with
⇒
Some32
⇒
Some64
_
⇒
None

As half_modulus(K, Half): half the modulus of an integer class k; the values from Half up to Mod - 1 are the negative ones when read as signed, in two's complement.

102Definition half_modulusk : class : optionZ ≔
match k with
⇒
Some2 ^ 31
⇒
Some2 ^ 63
_
⇒
None

The width of a store or of a data item, what size of value it writes: Wb and Wh are ir.pl's b and h, a byte and a 16-bit halfword, and the others are the classes w l p s d x.

112Inductive width: Type ≔
|Wb
|Wh
|Ww
|Wl
|Wp
|Ws
|Wd
|Wx

As width_bytes(Width, Size): the bytes a width w writes; an x87 extended float takes 10.

116Definition width_bytesw : width : Z ≔
match w with
⇒
1
⇒
2
⇒
4
⇒
8
⇒
8
⇒
4
⇒
8
⇒
10

A narrow integer type, the T of a narrow load and of ext(T): ir.pl's sw uw sh uh sb ub, a signed or unsigned word (4 bytes), halfword (2) or byte (1).

125Inductive narrow: Type ≔
|Sw
|Uw
|Sh
|Uh
|Sb
|Ub

Whether an integer is read as signed, in two's complement, or as unsigned.

129Inductive signedness: Type ≔
|Signed
|Unsigned

As narrow_type(T, Bytes, Signedness): the size in bytes and the signedness of the narrow type t.

133Definition narrow_typet : narrow : Z × signedness ≔
match t with
⇒
⇒
⇒

The type of a raw load: LdL for l, LdS, LdD and LdX for the float classes s d x, or a narrow type. This is load_type/1 without p, which RawLoadPointer reads instead.

144Inductive load_type: Type ≔
|LdL
|LdS
|LdD
|LdX
|LdNarrow
t : narrow

Ops

A comparison's Cond: eq and ne at any numeric class, the signed and unsigned orders at w and l, and le lt ge gt o (ordered) and uo (unordered) at a float class.

151Inductive cond: Type ≔
|Eq
|Ne
|Sle
|Slt
|Sge
|Sgt
|Ule
|Ult
|Uge
|Ugt
|Le
|Lt
|Ge
|Gt
|Ord
|Unord

The rights an access asks for: to read, or to write, which a read-only object refuses.

157Inductive rights: Type ≔
|Read
|Write

Equality of rights.

160Definition rights_eqbr r′ : rights : bool ≔
match r, r′ with
⇒
true
_, _
⇒
false

Which end of an object's bounds a half check tests natively, ir.pl's upper or lower; an earlier check proves the other.

166Inductive bound: Type ≔
|Upper
|Lower

One step of the protocol by which a pointer load or store moves an address and its capability, as pointer_memory_effects/2 lists them:

  • a heap load reads the aux word (AuxRead), resolves the lower from it (LowerResolve), then reads the address (AddressRead);
  • a heap store makes sure the aux exists (AuxEnsure), applies the collector's barrier to the stored lower (LowerBarrier), reloads its destination from a root (RootedReload), then writes the lower (LowerWrite) before the address (AddressWrite);
  • AtomicRead and AtomicWrite are Fil-C's atomic pointer helpers, each a whole protocol.
181Inductive effect: Type ≔
|AuxRead
|LowerResolve
|AddressRead
|AtomicRead
|AuxEnsure
|LowerBarrier
|RootedReload
|LowerWrite
|AddressWrite
|AtomicWrite

Equality of effects.

Equality of two effect lists, step by step.

196Definition effects_eqbes es′ : listeffect : bool ≔
lengthes =? lengthes′%nat && forallbλp ⇒ effect_eqbfstp sndp combinees es′

As pointer_memory_effects(load, Effects): the protocol of a heap pointer load, one of the two that evidence_preserving accepts.

201Definition load_effects: listeffect ≔

As pointer_memory_effects(local_load, Effects): the protocol of a pointer load from a named local, whose explicit stack aux has no atomic box, so there is no lower to resolve.

205Definition local_load_effects: listeffect ≔

An operation, the Op of a let (ir.pl's Ops table): one constructor per functor in the core subset, with the functor's parameters as its arguments. The arithmetic and conversions come first, then the alloc, the checks of the checked stage and their reuse forms, the raw loads and the variadic ops. What each reads is op_arg_classes.

213Inductive op: Type ≔
|Add
|Sub
|Mul
|Div
|Udiv
|Rem
|Urem
|And
|Or
|Xor
|Sar
|Shr
|Shl
|Neg
|Copy
|Ptoi
|Itop
|Cmp
c : cond k : class
1 if two values of class k compare by c, else 0
|Ext
t : narrow
the low bytes of a w, extended by t

The float conversions: ext(s) and ext(d) name their source class; stosi is FloatToIntSingle Signed, dtoui is FloatToIntDouble Unsigned; swtof is IntToFloatW Signed, ultof is IntToFloatL Unsigned.

|ExtF
k : class
widen a float of class k
|Truncd
|Truncx
|FloatToInt
k : class sg : signedness
a float of class k to an integer, truncated
|IntToFloat
k : class sg : signedness
an integer of class k to the nearest float
|Cast
the same bits at the other class: w and s, l and d
|Alloc
align : Z
a new zeroed heap object of the l size read
|Check
lo hi : Z r : rights align : Z
check of a pointer P: trap unless P may access from P+lo up to P+hi
|CheckAhead
lo hi : Z r : rights align ahi : Z
a check whose bytes from ahi up to hi are for a later access: check_ahead
|Renew
lo hi : Z r : rights align : Z
reuse a dominating check's bounds: renew
|RenewHull
lo hi : Z r : rights align : Z
a renew whose bounds two earlier proofs cover: renew_hull
|HalfCheck
b : bound lo hi : Z r : rights align : Z
a check that tests only the bound b: half_check
|SpanTest
lo hi : Z
1 if the pointer's object holds the span, else 0: span_test
|RenewIf
lo hi : Z r : rights align : Z
a check whose bounds a passing span test proves: renew_if
|Limit
size : Z
an opaque snapshot of the pointer's bounds: limit
|CheckLimit
lo hi : Z r : rights align : Z
a check of the bounds against a limit: check_limit
|CheckLocal
x : name off bytes : Z r : rights align : Z
prove an access to the named local x
|CheckFunction
trap unless the pointer is a function's exact address
|RawLoad
t : load_type off : Z
a non-pointer load at the proven address plus off
|RawLoadPointer
off : Z es : listeffect
a pointer load at the proven address plus off, by the protocol es

va_args takes a variadic function's entry argument snapshot at a byte offset; va_arg loads the next argument through a va_list.

|VaArgs
|VaArg

Values, instructions and jumps

A value an instruction reads (ir.pl's Values table).

249Inductive value: Type ≔
|Tmp
n : name
tmp(N), a temporary, defined once
|Const
n : Z
const(N), an integer; at a float class, its bit pattern
|Global
s : name
global(S), the address of the function or data object s

An argument of a flight's address computation: an l value, or address(P), the address bits of the pointer P.

256Inductive flight_arg: Type ≔
|FValue
v : value
|FAddress
p : value

A flight's Lower, where its capability comes from: none, or lower(P), exactly the capability of the pointer P.

260Inductive flight_lower: Type ≔
|LowerNone
|LowerOf
p : value

A call's Res, where its results go.

263Inductive call_result: Type ≔
|CVoid
void: none
|CResult
d : name k : class
result(tmp(D), K): the temporary d, of class k
|CTuple
rs : listname × class
tuple([result(tmp(D1), K1), ...]): a pair of results

As arg(K, Value): a call's argument, the value v passed at class k.

270Inductive arg: Type ≔
|Arg
k : class v : value

An instruction of a block, in the core subset; the table at the top of the page gives each one's ir.pl term. The raw forms do no checking of their own: they read a proof of class A or F.

275Inductive inst: Type ≔
|Let
d : name k : class o : op args : listvalue
d, of class k, is o of args
|Flight
d : name o : op args : listflight_arg lower : flight_lower
the pointer d: the address o computes, with the capability lower names
|RawStore
w : width off : Z v a : value
store v at the proven address a plus off
|RawStorePointer
off : Z v a : value es : listeffect
store the pointer v there, by the protocol es
|Call
r : call_result callee : value args : listarg
call callee, a symbol or a pointer
|RawCall
r : call_result callee : value args : listarg
call the proven function callee, of class F
|LocalAlloc
x : name size : Z
declare the named local x, of size zeroed bytes
|Loc
file : term line : Z
a source position; does nothing

A jump's target: L, or poll(L), a pollcheck on the edge before going to L.

287Inductive target: Type ≔
|To
l : name
|Poll
l : name

As edge_label(T, L): the label a target t goes to, polling or not.

291Definition edge_labelt : target : name ≔
match t with
Tol | Polll
⇒
l

The jump that ends a block (ir.pl's Jumps table).

294Inductive jump: Type ≔
|JGoto
t : target
goto(L)
|JBranch
v : value t1 t2 : target
to t1 if v is nonzero, else to t2
|JRet
v : value
ret(V): return v
|JRets
vs : listvalue
rets([V1, V2]): return a tuple
|JRetVoid
ret, from a void function
|JUnreachable
stop the program, a trap instruction

As phi(tmp(D), K, [Pred-Value]): a phi at the head of a block, defining d, of class k, as the value paired with the block control came from.

305Inductive phi: Type ≔
|Phi
d : name k : class pairs : listname × value

As block(Label, Phis, Insts, Jump): a block, its phis, then its instructions, then the one jump that ends it.

309Record block: Type ≔ mkBlock
b_label
 : name
b_phis
 : listphi
b_insts
 : listinst
b_jump
 : jump

A function's Ret: a class, void, or tuple([K1, K2]).

317Inductive ret_type: Type ≔
|RClass
k : class
|RVoid
|RTuple
ks : listclass
two words, a struct of 9 to 16 bytes

As func(Name, Linkage, Ret, Params, Blocks): a function.

323Record func: Type ≔ mkFunc
fn_name
 : name
fn_linkage
 : term
export, local or weak, kept as its term
fn_ret
fn_params
 : listclass × name
each a class and a temporary
fn_blocks
 : listblock
the entry block first

As variadic_func(Func): whether the function f takes the entry argument snapshot of a variadic function, which it does with a va_args anywhere in its blocks.

334Definition variadic_funcf : func : bool ≔
existsb
λ b  ⇒
existsb
λ i  ⇒
match i with
⇒
true
_
⇒
false

Data

A data object's Linkage (ir.pl's Data section). LExport, LLocal and LWeak are export, local and weak; LRo l is ro(L), read-only data, and LTls l is tls(L), an object each thread has its own instance of, both of the inner linkage l.

346Inductive linkage: Type ≔
|LExport
|LLocal
|LWeak
|LRo
l : term
|LTls
l : term
|LInit
which prio : term
init(ctor or dtor, Priority): a constructor or destructor table entry, not an object
|LExternWeak
extern(weak): a weak declaration of a symbol defined elsewhere, not an object
|LOther
t : term
any other Linkage term: valid_module/1 rejects it, so only the validator meets it

A data Item, a piece of a data object's initial contents. item(l, sym(Name, Off)) is plain mode's, outside the subset; item(p, sym(Name, Off)) is Sym.

356Inductive data_item: Type ≔
|Item
w : width n : Z
item(W, const(N)): n at width w
|Str
codes : listZ
item(b, str(Chars)): the bytes themselves
|Sym
s : name off : Z
a pointer to s plus off, with the capability of s
|Zero
n : Z
zero(N): n zero bytes
|ItemOther
t : term
any other term, kept as it is: valid_module/1 rejects it (data_item_shape/1), so only the validator meets it

As item_size(Item, Size0, Size): the bytes a data item takes.

364Definition item_sizeit : data_item : Z ≔
match it with
Strcs
⇒
Z.of_natlengthcs
Sym_ _
⇒
8
⇒
n

The bytes a list of data items takes, the size of the object they make.

375Definition items_sizeits : listdata_item : Z ≔
fold_leftλs it ⇒ s + item_sizeit its 0

Modules

An item of a module; the table at the top of the page gives each one's ir.pl term.

383Inductive item: Type ≔
|IFunc
f : func
a function of the core subset
|IOutside
n : name t : term
a function outside it: an address, no body
|IData
n : name lk : linkage align : Z items : listdata_item
a data object
|IAlias
n : name lk : term target : name
a second symbol n for the function or data object target

A module, as module(Items): its items in order.

390Definition module ≔
listitem

Facts about instructions

As op_arg_classes(Op, K, filc, Classes): the classes at which the op o reads its arguments when its result has class k; none where o cannot have a result of class k.

397Definition op_arg_classeso : op k : class : optionlistclass ≔
match o with
⇒
match k with
⇒
SomeW; W
⇒
SomeL; L
⇒
SomeP; L
_
⇒
None
Mul | Div | Udiv | Rem | Urem | And | Or | Xor
⇒
Somek; k
Sar | Shr | Shl
⇒
Somek; W
⇒
Somek
⇒
SomeP
⇒
SomeL
Cmp_ ck
⇒
Someck; ck
⇒
SomeW
⇒
Somefk
⇒
Somefk
⇒
Someik
⇒
match k with
⇒
SomeSingle
⇒
SomeW
⇒
SomeDouble
⇒
SomeL
_
⇒
None
⇒
SomeL
Check_ _ _ _ | CheckAhead_ _ _ _ _
⇒
SomeP
Renew_ _ _ _
⇒
SomeA; P
RenewHull_ _ _ _
⇒
SomeA; A; P
HalfCheck_ _ _ _ _
⇒
SomeA; P
⇒
SomeP
RenewIf_ _ _ _
⇒
SomeP; W
⇒
SomeP
CheckLimit_ _ _ _
⇒
SomeP; L
CheckLocal_ _ _ _ _
⇒
Some[ ]
⇒
SomeA
⇒
SomeA
⇒
SomeL
⇒
SomeP

Whether the value v is a symbol's address, a Global.

443Definition is_globalv : value : bool ≔
match v with
⇒
true
_
⇒
false

As evidence_preserving(Inst): the instruction i reaches no safepoint and cannot free an object or change its bounds or rights, so the evidence of checks before it still holds after it.

450Definition evidence_preservingi : inst : bool ≔
match i with
Loc_ _
⇒
true
Flight_ _ _ _
⇒
true
Let_ A Check_ _ _ _ _ | Let_ A CheckAhead_ _ _ _ _ _ | Let_ A Renew_ _ _ _ _ | Let_ A RenewHull_ _ _ _ _ | Let_ A HalfCheck_ _ _ _ _ _ | Let_ W SpanTest_ _ _ | Let_ A RenewIf_ _ _ _ _ | Let_ L Limit_ _ | Let_ A CheckLimit_ _ _ _ _
⇒
true
Let_ _ RawLoad_ _ _
⇒
true
RawStorew _ _ _
⇒
match w with
⇒
false
_
⇒
true
Let_ _ Add | Sub | Mul | Div | Udiv | Rem | Urem | And | Or | Xor | Sar | Shr | Shl | Neg | Ptoi _
⇒
true
Let_ _ Cmp_ _ _
⇒
true
Let_ _ Ext_ _
⇒
true
⇒
true
Let_ _ Copy args
⇒
negbexistsbis_global args
_
⇒
false

As ahead_transparent(Inst): the instruction i may come between a check_ahead and the access whose need it checks early. It is evidence_preserving, and not a division, whose fault would end the program otherwise than a Fil-C trap.

476Definition ahead_transparenti : inst : bool ≔
&&
match i with
Let_ _ Div | Udiv | Rem | Urem _
⇒
false
_
⇒
true

As local_objects(Func, Objects): the named locals the function f declares, each with its size, in instruction order.

485Definition local_objectsf : func : listname × Z ≔
flat_map
λ b  ⇒
flat_map
λ i  ⇒
match i with
⇒
x, size
_
⇒
[ ]