-
Notifications
You must be signed in to change notification settings - Fork 243
Machine integers
F* machine integers are all implemented in modules called FStar.IntN for signed integers, and FStar.UIntN for unsigned integers, where N is the number of bits the integer is encoded on.
F* currently offers support for:
- char and unsigned char (
FStar.Int8andFStar.UInt8) - short and unsigned short (
FStar.Int16andFStar.UInt16) - int31 and unsigned int31, which are the OCaml native integers on 32-bit platforms (
FStar.Int31andFStar.UInt31) - int32 and unsigned int32 (
FStar.Int32andFStar.UInt32) - int63 and unsigned int63, which are the OCaml native integers on 64-bit platforms (
FStar.Int63andFStar.UInt63) - int64 and unsigned int64 (
FStar.Int64andFStar.UInt64) - int128 and unsigned int128 which are non-standard but supported by certain C compilers (
FStar.Int128andFStar.UInt128)
All those modules have similar structures and expose the same operators:
- a type
t, which is the type of the machine integers of that module. E.g. the type ofint64isFStar.UInt64.t. - a function
val v: t -> Tot intwhich returns the integer value of a machine integer. - the
nconstant defines the number of bits the machine integer is encoded on. - a
sizepredicate which specifies the range of mathematical integer values that can be encoded on the machine integer. - a
val (u)int_to_t: x:t{size x n} -> Tot tfunction that converts a mathematical integer to a machine integer encoding that value. - the
max_int nandmin_int nvalues define the maximum and minimum values that can be represented by the machine integers of the given module. (e.g.-128and127for shorts). - [
add|sub|mul] operators are strictly non-overflowing addition, subtraction and multiplication, which means that the proof system checks the absence of overflows before typechecking. - [
add|sub|mul]_modare addition, subtraction and multiplication with wrapping semantics. - [
add|sub|mul]_underspecare underspecified non-overflowing addition, subtraction and multiplication, which means that if the proof system cannot assert the absence of overflows, the result of the operation will be undefined. -
divandremare the division and the remainder. For signed integers, those are the flooring division and the signed remainder and NOT the respective euclidian versions. -
shift_leftandshift_rightare the shift operators. The right operand must be smaller that the number of bits the integer represents (e.g. for an int32, the right operand has to be less than or equal to 31). -
logand,logor,logxorandlognotare bitwise operators to compute&,|,^and~. -
eq,gte,gt,lte,ltare boolean comparison that compute 'equals', 'greater than or equal', 'greater than', 'lower than or equal', 'lower than'. -
of_stringandto_stringallow to use of constants in the code. However as the format of the string is not currently checked to be proper, the use of theof_stringfunction is unsound and should be avoided. Machine integer constants should be used instead (see section below).
For convenience, those modules also define infix operators for most of those functions, which is the usual infix operator post-fixed by the ^ symbol:
- [add|sub|mul] ==> [
+|-|*]^ - [add|sub|mul]_mod ==> [
+|-|*]%^ - [add|sub|mul]_underspec ==> [
+|-|*]?^ - div ==>
/^ - rem ==>
%^ - shift_left ==>
<<^ - shift_right ==>
>>^ - logand, logor, logxor ==>
&^,|^,^^
F* uses the following syntax for machine integer values:
- constants can be written in decimal, binary, octal or hexadecimal form:
-
0b10stands for 2 -
0o10stands for 8 -
10stands for 10 -
0x10stands for 16
-
- suffixes allow the parser to pick the right size and sign:
-
1yand1uyforFStar.Int8andFStar.UInt8 -
1sand1usforFStar.Int16andFStar.UInt16 -
1land1ulforFStar.Int32andFStar.UInt32 -
1Land1uLforFStar.Int64andFStar.UInt64
-
Those prefixes and suffixes can be freely combined. E.g. 0x10ul is the FStar.UInt32.t value encoding 16.
F* does not support overloading. The infix operators will be those of the last opened FStar.(U)IntN module.
The F* parser supports namespace scoping to help manipulating values of different machine integer types. For instance one can write:
let word = let open FStar.Int32 in 0l +^ 1l in
let word' = let open FStar.Int64 in 0L +^ 0L in
...Or, alternatively:
let word = FStar.Int32.( 0l +^ 1l ) in
let word' = FStar.Int64.( 0L +^ 0L ) in
...Those modules have OCaml (all modules) and C ((U)Int[8|16|32|64|128], via KreMLin) realization. The OCaml realized modules link to:
- native OCaml integers for (U)Int8,16,31,32,63, assuming a 64-bit platform. That implies that concretely, all machine integers smaller than 63 bits will be encoded as 63 bits integers, for performance.
- Boxed integers from the Stdint OCaml library. E.g.
FStar.Int64goes toStdint.Int64in OCaml.
It is assumed that the default type for machine integers in F* is FStar.UInt32.t. Hence indexes, lengths or counters should be of that type.
Some modules define additional type and operators:
-
FStar.UInt8defines the typebyte(unsigned char) - the unsigned
FStar.UIntNmodules define two masking operators:-
eq_maskwhich compares two operands and returns 0xff...ff if they are equal, 0x0..0 otherwise -
gte_maskwhich compares two operands and returns 0xff...ff if the first one is greater than or equal to the other, 0x0..0 otherwise
-
- the
FStar.(u)Int128modules define amul_wideoperator which takes twoFStar.(U)Int64.tintegers and return aFStar.(U)Int128.tresult.