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.
(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
LispWorks 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 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 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 - 20 Sep 2017