All Manuals > LispWorks® User Guide and Reference Manual > 28 Miscellaneous Utilities

28.2 Optimized integer arithmetic and integer vector access

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.

28.2.1 Typed aref vectors

You can make vectors of certain element types which allow the most efficient access possible when compiled with suitable optimize qualities.

To do this:

  1. Make a vector with make-typed-aref-vector.
  2. Access the vector using typed-aref and (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.

  3. Compile the access with 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.

28.2.2 Fast 32-bit arithmetic

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.

28.2.2.1 Optimized and unoptimized INT32 code

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.

28.2.2.2 The INT32 API

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.

28.2.2.3 INT32 Optimization

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)

28.2.3 Fast 64-bit arithmetic

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.

28.2.3.1 Optimized and unoptimized INT64 code

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.

28.2.3.2 The INT64 API

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.

28.2.3.3 INT64 Optimization

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)

28.2.4 Integer vector access

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