-
Notifications
You must be signed in to change notification settings - Fork 233
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.Int8
andFStar.UInt8
) - short and unsigned short (
FStar.Int16
andFStar.UInt16
) - int31 and unsigned int31, which are the OCaml native integers on 32-bit platforms (
FStar.Int31
andFStar.UInt31
) - int32 and unsigned int32 (
FStar.Int32
andFStar.UInt32
) - int63 and unsigned int63, which are the OCaml native integers on 64-bit platforms (
FStar.Int63
andFStar.UInt63
) - int64 and unsigned int64 (
FStar.Int64
andFStar.UInt64
) - int128 and unsigned int128 which are non-standard but supported by certain C compilers (
FStar.Int128
andFStar.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 ofint64
isFStar.UInt64.t
. - a function
val v: t -> Tot int
which returns the integer value of a machine integer. - the
n
constant defines the number of bits the machine integer is encoded on. - a
size
predicate 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 t
function that converts a mathematical integer to a machine integer encoding that value. - the
max_int n
andmin_int n
values define the maximum and minimum values that can be represented by the machine integers of the given module. (e.g.-128
and127
for 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
]_mod
are addition, subtraction and multiplication with wrapping semantics. - [
add
|sub
|mul
]_underspec
are 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. -
div
andrem
are the division and the remainder. For signed integers, those are the flooring division and the signed remainder and NOT the respective euclidian versions. -
shift_left
andshift_right
are 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
,logxor
andlognot
are bitwise operators to compute&
,|
,^
and~
. -
eq
,gte
,gt
,lte
,lt
are boolean comparison that compute 'equals', 'greater than or equal', 'greater than', 'lower than or equal', 'lower than'. -
of_string
andto_string
allow 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_string
function 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:
-
0b10
stands for 2 -
0o10
stands for 8 -
10
stands for 10 -
0x10
stands for 16
-
- suffixes allow the parser to pick the right size and sign:
-
1y
and1uy
forFStar.Int8
andFStar.UInt8
-
1s
and1us
forFStar.Int16
andFStar.UInt16
-
1l
and1ul
forFStar.Int32
andFStar.UInt32
-
1L
and1uL
forFStar.Int64
andFStar.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.Int64
goes toStdint.Int64
in 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.UInt8
defines the typebyte
(unsigned char
) - the unsigned
FStar.UIntN
modules define two masking operators:-
eq_mask
which compares two operands and returns 0xff...ff if they are equal, 0x0..0 otherwise -
gte_mask
which 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)Int128
modules define amul_wide
operator which takes twoFStar.(U)Int64.t
integers and return aFStar.(U)Int128.t
result.