1 ;;;; This file contains stuff for controlling floating point traps. It
2 ;;;; is IEEE float specific, but should work for pretty much any FPU
3 ;;;; where the state fits in one word and exceptions are represented
4 ;;;; by bits being set.
6 ;;;; This software is part of the SBCL system. See the README file for
9 ;;;; This software is derived from the CMU CL system, which was
10 ;;;; written at Carnegie Mellon University and released into the
11 ;;;; public domain. The software is in the public domain and is
12 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
13 ;;;; files for more information.
17 (eval-when (:compile-toplevel :load-toplevel :execute)
19 (defparameter *float-trap-alist*
20 (list (cons :underflow float-underflow-trap-bit)
21 (cons :overflow float-overflow-trap-bit)
22 (cons :inexact float-inexact-trap-bit)
23 (cons :invalid float-invalid-trap-bit)
24 (cons :divide-by-zero float-divide-by-zero-trap-bit)
25 #!+x86 (cons :denormalized-operand float-denormal-trap-bit)))
27 (defparameter *rounding-mode-alist*
28 (list (cons :nearest float-round-to-nearest)
29 (cons :zero float-round-to-zero)
30 (cons :positive-infinity float-round-to-positive)
31 (cons :negative-infinity float-round-to-negative)))
34 (defparameter *precision-mode-alist*
35 (list (cons :24-bit float-precision-24-bit)
36 (cons :53-bit float-precision-53-bit)
37 (cons :64-bit float-precision-64-bit)))
39 ;;; Return a mask with all the specified float trap bits set.
40 (defun float-trap-mask (names)
43 (or (cdr (assoc x *float-trap-alist*))
44 (error "unknown float trap kind: ~S" x)))
48 ;;; interpreter stubs for floating point modes get/setters for the
49 ;;; alpha have been removed to alpha-vm.lisp, as they are implemented
50 ;;; in C rather than as VOPs.
53 (defun floating-point-modes ()
54 (floating-point-modes))
55 (defun (setf floating-point-modes) (new)
56 (setf (floating-point-modes) new)))
58 ;;; This function sets options controlling the floating-point
59 ;;; hardware. If a keyword is not supplied, then the current value is
60 ;;; preserved. Possible keywords:
62 ;;; A list of the exception conditions that should cause traps.
63 ;;; Possible exceptions are :UNDERFLOW, :OVERFLOW, :INEXACT, :INVALID,
64 ;;; :DIVIDE-BY-ZERO, and on the X86 :DENORMALIZED-OPERAND.
67 ;;; The rounding mode to use when the result is not exact. Possible
68 ;;; values are :NEAREST, :POSITIVE-INFINITY, :NEGATIVE-INFINITY and
69 ;;; :ZERO. Setting this away from :NEAREST is liable to upset SBCL's
70 ;;; maths routines which depend on it.
72 ;;;:CURRENT-EXCEPTIONS
73 ;;;:ACCRUED-EXCEPTIONS
74 ;;; These arguments allow setting of the exception flags. The main
75 ;;; use is setting the accrued exceptions to NIL to clear them.
78 ;;; Set the hardware's \"fast mode\" flag, if any. When set, IEEE
79 ;;; conformance or debuggability may be impaired. Some machines don't
80 ;;; have this feature, and some SBCL ports don't implement it anyway
81 ;;; -- in such cases the value is always NIL.
83 ;;;:PRECISION (x86 only) :24-bit, :53-bit and :64-bit, for the
84 ;;;internal precision of the mantissa.
86 ;;; GET-FLOATING-POINT-MODES may be used to find the floating point modes
87 ;;; currently in effect. See cold-init.lisp for the list of initially
90 (defun set-floating-point-modes (&key (traps nil traps-p)
91 (rounding-mode nil round-p)
92 (current-exceptions nil current-x-p)
93 (accrued-exceptions nil accrued-x-p)
94 (fast-mode nil fast-mode-p)
95 #!+x86 (precision nil precisionp))
96 (let ((modes (floating-point-modes)))
98 (setf (ldb float-traps-byte modes) (float-trap-mask traps)))
100 (setf (ldb float-rounding-mode modes)
101 (or (cdr (assoc rounding-mode *rounding-mode-alist*))
102 (error "unknown rounding mode: ~S" rounding-mode))))
104 (setf (ldb float-exceptions-byte modes)
105 (float-trap-mask current-exceptions)))
107 (setf (ldb float-sticky-bits modes)
108 (float-trap-mask accrued-exceptions)))
111 (setq modes (logior float-fast-bit modes))
112 (setq modes (logand (lognot float-fast-bit) modes))))
115 (setf (ldb float-precision-control modes)
116 (or (cdr (assoc precision *precision-mode-alist*))
117 (error "unknown precision mode: ~S" precision))))
118 ;; FIXME: This apparently doesn't work on Darwin
119 #!-darwin (setf (floating-point-modes) modes))
123 ;;; This function returns a list representing the state of the floating
124 ;;; point modes. The list is in the same format as the &KEY arguments to
125 ;;; SET-FLOATING-POINT-MODES, i.e.
126 ;;; (apply #'set-floating-point-modes (get-floating-point-modes))
127 ;;; sets the floating point modes to their current values (and thus is a
129 (defun get-floating-point-modes ()
130 (flet ((exc-keys (bits)
133 ,@(mapcar (lambda (x)
134 `(when (logtest bits ,(cdr x))
139 (let ((modes (floating-point-modes)))
140 `(:traps ,(exc-keys (ldb float-traps-byte modes))
141 :rounding-mode ,(car (rassoc (ldb float-rounding-mode modes)
142 *rounding-mode-alist*))
143 :current-exceptions ,(exc-keys (ldb float-exceptions-byte modes))
144 :accrued-exceptions ,(exc-keys (ldb float-sticky-bits modes))
145 :fast-mode ,(logtest float-fast-bit modes)
147 #!+x86 ,(car (rassoc (ldb float-precision-control modes)
148 *precision-mode-alist*))))))
150 ;;; Return true if any of the named traps are currently trapped, false
152 (defmacro current-float-trap (&rest traps)
153 `(not (zerop (logand ,(dpb (float-trap-mask traps) float-traps-byte 0)
154 (floating-point-modes)))))
156 ;;; Signal the appropriate condition when we get a floating-point error.
157 (defun sigfpe-handler (signal info context)
158 (declare (ignore signal info))
159 (declare (type system-area-pointer context))
160 (let* ((modes (context-floating-point-modes
161 (sb!alien:sap-alien context (* os-context-t))))
162 (traps (logand (ldb float-exceptions-byte modes)
163 (ldb float-traps-byte modes))))
164 (cond ((not (zerop (logand float-divide-by-zero-trap-bit traps)))
165 (error 'division-by-zero))
166 ((not (zerop (logand float-invalid-trap-bit traps)))
167 (error 'floating-point-invalid-operation))
168 ((not (zerop (logand float-overflow-trap-bit traps)))
169 (error 'floating-point-overflow))
170 ((not (zerop (logand float-underflow-trap-bit traps)))
171 (error 'floating-point-underflow))
172 ((not (zerop (logand float-inexact-trap-bit traps)))
173 (error 'floating-point-inexact))
175 ((zerop (ldb float-exceptions-byte modes))
176 ;; I can't tell what caused the exception!!
177 (error 'floating-point-exception
178 :traps (getf (get-floating-point-modes) :traps)))
180 (error 'floating-point-exception)))))
182 ;;; Execute BODY with the floating point exceptions listed in TRAPS
183 ;;; masked (disabled). TRAPS should be a list of possible exceptions
184 ;;; which includes :UNDERFLOW, :OVERFLOW, :INEXACT, :INVALID and
185 ;;; :DIVIDE-BY-ZERO and on the X86 :DENORMALIZED-OPERAND. The
186 ;;; respective accrued exceptions are cleared at the start of the body
187 ;;; to support their testing within, and restored on exit.
188 (defmacro with-float-traps-masked (traps &body body)
189 (let ((traps (dpb (float-trap-mask traps) float-traps-byte 0))
190 (exceptions (dpb (float-trap-mask traps) float-sticky-bits 0))
191 (trap-mask (dpb (lognot (float-trap-mask traps))
192 float-traps-byte #xffffffff))
193 (exception-mask (dpb (lognot (float-trap-mask traps))
194 float-sticky-bits #xffffffff))
195 (orig-modes (gensym)))
196 `(let ((,orig-modes (floating-point-modes)))
199 (setf (floating-point-modes)
200 (logand ,orig-modes ,(logand trap-mask exception-mask)))
202 ;; Restore the original traps and exceptions.
203 (setf (floating-point-modes)
204 (logior (logand ,orig-modes ,(logior traps exceptions))
205 (logand (floating-point-modes)
206 ,(logand trap-mask exception-mask))))))))