This section describes ways to perform certain operations as efficiently as possible, including vector access and raw 32-bit arithmetic. Additionally in 64-bit LispWorks, raw 64-bit arithmetic is possible.
You can make vectors of certain element types which allow the most efficient access possible when compiled with suitable optimize qualities.
To do this:
(setf typed-aref)
with a type argument of double-float, float, single-float, int32, (unsigned-byte n)
or (signed-byte n)
where n = 8, 16 or 32.
Additionally, in 64-bit LispWorks the types (unsigned-byte 64)
and (signed-byte 64)
are supported.
safety 0
(and for float types, float 0
) and a constant type.
See typed-aref for more details and examples.
Efficient access to foreign arrays is also available. See fli:foreign-typed-aref in the Foreign Language Interface User Guide and Reference Manual.
The INT32 API provides a way to perform optimal raw 32-bit arithmetic. Note that, unlike Lisp integer types, this is modulo 2^32 like the C int
type.
The INT32 symbols are all in the system
package.
The Lisp type int32 reads 32 bits of memory, like (signed-byte 32)
, but the data is in int32 format for use with the INT32 API.
When optimized correctly, the intermediate int32 objects are not constructed.
In unoptimized code, sequences of operations like:
(sys:int32+ (sys:int32- a b) (sys:int32- c d))
will generate intermediate int32 objects for the results of the subtraction, but the compiler can optimize these away because it knows that the function int32+ consumes int32 objects.
Note: the INT32 API is not designed to optimize sys:int32 objects passed as arguments.
The INT32 API contains the type int32, a vector type simple-int32-vector and accessor, functions to convert int32 to and from integer, some constant int32 values, and a full range of operators for mod 2^32 arithmetic.
You can find all these by evaluating:
(apropos "INT32" "SYSTEM" t)
For details for each, see the entries starting with int32 in 47 The SYSTEM Package.
The optimization works safely but without boxing when possible. You need:
(optimize (float 0))
to get the optimization. This float level affects whether INT32 operations are optimized. This declaration must be placed at the start of a function (not on an inner let or locally form).
In this example the safety level assures a second optimization in fli:foreign-typed-aref:
(defun incf-signed-byte-32 (ptr index) (declare (optimize (safety 0) (float 0)) (type fixnum index)) (setf (fli:foreign-typed-aref 'sys:int32 ptr index) (sys:int32-1+ (fli:foreign-typed-aref 'sys:int32 ptr index))) ;; return ptr, since otherwise the int32 would ;; need to be boxed to return it ptr)
The INT64 API provides a way to perform optimal raw 64-bit arithmetic. Note that, unlike Lisp integer types, this is modulo 2^64 like the C long
long
or int64 types.
The INT64 symbols are all in the system
package.
The Lisp type int64 reads 64 bits of memory, like (signed-byte 64)
, but the data is in int64 format for use with the INT64 API.
When optimized correctly, the intermediate int64 objects are not constructed.
In unoptimized code, sequences of operations like:
(sys:int64+ (sys:int64- a b) (sys:int64- c d))
will generate intermediate int64 objects for the results of the subtraction, but the compiler can optimize these away because it knows that the function int64+ consumes int64 objects.
Note: the INT64 API is not designed to optimize sys:int64 objects passed as arguments.
The INT64 API contains the type int64, a vector type simple-int64-vector and accessor, functions to convert int64 to and from integer, some constant int64 values, and a full range of operators for mod 2^64 arithmetic.
You can find all these by evaluating:
(apropos "INT64" "SYSTEM" t)
For details for each, see the entries starting with int64 in 47 The SYSTEM Package.
INT64 optimization occurs only in 64-bit LispWorks. The INT64 API is not optimized in 32-bit LispWorks.
The optimization works safely but without boxing when possible. You need:
(optimize (float 0))
to get the optimization. This float level affects whether INT64 operations are optimized. This declaration must be placed at the start of a function (not on an inner let or locally form).
In this example the safety level assures a second optimization in fli:foreign-typed-aref:
(defun incf-signed-byte-64 (ptr index) (declare (optimize (safety 0) (float 0)) (type fixnum index)) (setf (fli:foreign-typed-aref 'sys:int64 ptr index) (sys:int64-1+ (fli:foreign-typed-aref 'sys:int64 ptr index))) ;; return ptr, since otherwise the int64 would ;; need to be boxed to return it ptr)
octet-ref and base-char-ref (and their setters) are provided to allow efficient access to simple vectors of element type (unsigned-byte 8)
or base-char (that is, simple-base-strings) in the same code.
Other vector types are accepted, but for these specific string and binary vector types octet-ref and base-char-ref match what aref and (setf aref)
do except that they always take and return the same value/result type, and they are also more efficient than aref.
Use octet-ref and base-char-ref according to whether you work with elements of type integer or base-char.
LispWorks® User Guide and Reference Manual - 01 Dec 2021 19:30:25