rocq/theories/Ops.v
Integer arithmetic and the evaluation of ops, transcribed from interp.pl's Operations section: alu/4, additive_res/4 and kind_res/8 for the core subset.
Integers of class K are 0..2^bits(K)-1; signed readings, shift counts and divisions follow the interpreter clause by clause. Fil-C defines division by zero as 0 and MIN / −1 as MIN (docs/ub.md), so integer arithmetic never has undefined behaviour here.
op_res gives an op's partial result, or asks for an allocation: alloc is the only op whose result depends on a choice, the fresh base of its object (Memory.v's fresh).
Integers
As sign_extension(M, H, U, S): the two's-complement reading of the low bits of u, for a field of modulus m with sign threshold h, from which values read as negative.
As signed(K, U, S): the integer u of class k read as signed; none for a class that is not an integer class.
As extension(T, X, S): the low bytes of x that the narrow type t names, sign- or zero-extended.
As cond_bit(Cond, K, X, Y, B): 1 when x c y holds at the integer class k, else 0; a float condition has none here (float_compare).
As shift_factor(K, Y, P): the power of two a shift by y at class k multiplies or divides by; the count is taken modulo the class width.
As unsigned_division/4: the division or remainder f of x by y, where a zero divisor gives 0.
As signed_division/5: the division or remainder f of x by y read as signed at class k. A zero divisor gives 0, and the quotient truncates toward zero (Prolog's // and rem), then wraps, so the most negative value divided by -1 is itself.
As alu(Op, K, Xs, Res): the integer op o of class k on the words xs, wrapping to the class's modulus; add and sub are integer here (additive_res adds to pointers). No word for arguments of the wrong form.
Checks
As checked_res(Res0, P, Res): a check's result from its access check r: the pointer p, now proven, or r's trap.
As raw_res(Res0, Res): a raw access is the access its check covers, made again without trapping; what would have trapped is unchecked.
As half_bound(Bound, B, Size, Base, End, Life): the one bound a half check tests natively, for size bytes at the address b of the object from base up to end_ of life l. The upper bound holds if the bytes end at or below end_; the lower if base is at or below b read as signed, and never for a freed object.
As half_passes(Bound, Mem, B, Size, Cap, Rights, Align, Passes): a half check's whole native test at the address b: the bound bd, the read-only flag for a write, and the alignment. Its inner none is for a capability that is not an object's, whose header no half check may read.
Loads
As extended_res(Res0, T, K, Res) of a loaded u: u extended from the narrow type t, as a word of class k.
As load_op_res(T, K, filc, [ptr(A, Cap)], ...) for a non-pointer load type t: the access check of the address a through the capability c (read, alignment 1), then the bytes, extended for a narrow t.
As pointer_load_effects_res(ok, Effects, A, Mem0, val(P), Mem): the pointer the protocol es loads from the address a, run from loaded(none, ptr(0, none)).
As pointer_store_effect(A, P, Effect, Mem0, Mem): one step e of storing the pointer x at the address a. Ensure, barrier and reload are identities here (no garbage collector, no aux allocation); the writes happen in list order, the lower before the primary address.
The memory after a pointer store's protocol es, each step by pointer_store_effect in turn.
Stores
As store_res(filc, Width, Mem0, ptr(A, Cap), X, Res, Mem): a store of the word x at width w to the address a through the capability c. The access check (alignment 8 for a pointer and for x, else 1, width_word/5), then its bytes, and for a pointer its capability in aux; a failed check leaves memory as it was.
Variadic arguments
The width a store of a value of class k writes, as width_bytes(K, Size) reads a class as a width; none for a proof class.
As va_cell(K, Step, Align): a va_arg of class k takes Step bytes at an Align-aligned cursor, as Fil-C's runtime does: a long double's cell is 16 bytes at 16, of which it reads its 10.
As kind_res(va_arg, _, K, filc, [P], S0, Res, S): the next variadic argument, of class k, through the va_list p. The cursor is the pointer stored at p (pointer_load_res/5); its cell is checked for reading, the cursor moves past it with an l store at p, and the value is the cell's bytes, a pointer with its stored capability for p (va_cursor_res/6 and va_checked_res/8).
Ops
What an op yields: a partial result and the memory after it, undefined behaviour (ub(Why), only an invalid float-to-integer conversion here), or a request for a fresh object and what follows from its base.
| | | OpRes | ||
| | | OpUB | why : term | ub(Why) |
| | | OpAlloc | allocate q; k gives the result and the memory for its fresh base |
Floats
The ieee.pl format of a float class k; none for the others.
The ieee.pl condition of a comparison's condition c; none for the integer orders, which condition/2 never holds.
As op_res(cmp(C, CK), ...) at a float CK: 1 if the bit patterns a and b of format ck compare by c, else 0 (ieee_compare/5).
As float_arithmetic(Op, K, Xs, R): add, sub, mul, div, neg and copy in the float format k, on bit patterns. A copy only checks that its word is an integer.
As kind_res(float_convert, Op, K, ...): the float x converted by the op o to class k, rounded to nearest: ext(s) to any float class, ext(d) to x, truncd to s, truncx to any float class, and sqrt, the square root at k (ieee_sqrt).
As float_integer(Op, K, X, Res): the float x of format from truncated toward zero, if it is finite and fits the class k signed or unsigned, else the undefined behaviour ub(float_conversion).
As integer_source(Op, X, N): the integer an int-to-float op reads from the word x of class ik, signed or unsigned.
As kind_res/8 for the core subset's integer, pointer and checked ops: what the op o of result class k does on the words xs in the memory m, or none where the interpreter fails (arguments of the wrong form, a capability it cannot follow, or a setjmp, which kind_res/8 refuses since it does not return twice). The checks read memory and never change it; Alloc asks for an allocation.
As op_res(Op, K, filc, Args, S0, Res, S) and kind_res/8 for the core subset: what the op o of result class k does on the words xs in the memory m. A float comparison and float arithmetic come first, as op_res/7 commits to them before the integer dispatch of op_res_int.