1 ;;;; generic type testing and checking apparatus
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
13 (defparameter *immediate-types
*
14 (list unbound-marker-widetag character-widetag
15 #!+64-bit single-float-widetag
))
17 (defparameter *fun-header-widetags
*
18 (list funcallable-instance-header-widetag
19 simple-fun-header-widetag
20 closure-header-widetag
))
22 ;; Given a list of widetags in HEADERS, compress into a minimal list of ranges
23 ;; and/or singletons that should be tested.
24 ;; FIXME: At present the "is it effectively a one-sided test" is re-implemented
25 ;; in an ad-hoc way by each backend. The range convention should be
26 ;; changed to indicate explicitly when either limit needn't be checked.
27 ;; (Use NIL or * as a bound perhaps)
28 (defun canonicalize-headers (headers)
32 (delta (- other-immediate-1-lowtag other-immediate-0-lowtag
)))
34 (results (if (= start prev
)
37 ;; COPY-LIST because the argument may come from immutable source code
38 (dolist (header (sort (copy-list headers
) #'<))
42 ((= header
(+ prev delta
))
51 ;; If WIDETAGS is comprised of two ranges that are nearly adjacent,
52 ;; return a single range spanning both original ranges,
53 ;; and as a second value the widetag(s) to exclude;
54 ;; or return the unmodified ranges and NIL.
55 ;; This could be generalized: three ranges that collapse to one with at most
56 ;; two exceptions, or three collapsing to two with one exception, etc.
57 (defun canonicalize-headers-and-exceptions (widetags)
58 (let ((ranges (canonicalize-headers widetags
)))
59 (if (and (cdr ranges
) (endp (cddr ranges
))
60 (listp (car ranges
)) (listp (cadr ranges
)) ; 2 ranges
61 (let ((end-range-1 (cdar ranges
))
62 (start-range-2 (caadr ranges
)))
63 (= start-range-2
(+ end-range-1
8))))
64 ;; Return ((start-range-1 . end-range-2))
65 (values (list (cons (caar ranges
) (cdadr ranges
)))
66 (list (+ (cdar ranges
) 4))) ; the excluded value
67 (values ranges nil
))))
69 (defmacro test-type
(value target not-p
72 &key
&allow-other-keys
)
73 ;; Determine what interesting combinations we need to test for.
74 (let* ((type-codes (mapcar #'eval type-codes
))
75 (fixnump (and (every (lambda (lowtag)
76 (member lowtag type-codes
))
77 '#.
(mapcar #'symbol-value fixnum-lowtags
))
79 (lowtags (remove lowtag-limit type-codes
:test
#'<))
80 (extended (remove lowtag-limit type-codes
:test
#'>))
81 (immediates (intersection extended
*immediate-types
* :test
#'eql
))
82 ;; To collapse the range of widetags comprising real numbers on 64-bit
83 ;; machines, consider SHORT-FLOAT-WIDETAG both a header and immediate.
84 ;; No OTHER-POINTER-LOWTAG object can ever have that header tag.
85 ;; But only do so if there would otherwise be a discontinuity
86 ;; in the set of headers.
87 ;; Another approach would have been to flip DOUBLE- and SINGLE- float,
88 ;; but that would not help NUMBERP, only REALP. Putting SINGLE-
89 ;; after the complex widetags would work but harm 32-bit machines.
90 (headers (set-difference
92 (if (and (= n-word-bits
64)
93 (member (- single-float-widetag
4) extended
)
94 (member (+ single-float-widetag
4) extended
))
95 (remove single-float-widetag
*immediate-types
*)
98 (function-p (if (intersection headers
*fun-header-widetags
*)
99 (if (subsetp headers
*fun-header-widetags
*)
101 (error "can't test for mix of function subtypes ~
102 and normal header types"))
105 (error "At least one type must be supplied for TEST-TYPE."))
108 (when (remove-if (lambda (x)
109 (member x
'#.
(mapcar #'symbol-value fixnum-lowtags
)))
111 (error "can't mix fixnum testing with other lowtags"))
113 (error "can't mix fixnum testing with function subtype testing"))
115 ((and (= n-word-bits
64) immediates headers
)
116 `(%test-fixnum-immediate-and-headers
,value
,target
,not-p
118 ',(canonicalize-headers
122 (if (= n-word-bits
64)
123 `(%test-fixnum-and-immediate
,value
,target
,not-p
126 (error "can't mix fixnum testing with other immediates")))
128 `(%test-fixnum-and-headers
,value
,target
,not-p
129 ',(canonicalize-headers headers
)
132 `(%test-fixnum
,value
,target
,not-p
137 (if (= n-word-bits
64)
138 `(%test-immediate-and-headers
,value
,target
,not-p
140 ',(canonicalize-headers headers
)
142 (error "can't mix testing of immediates with testing of headers")))
144 (error "can't mix testing of immediates with testing of lowtags"))
146 (error "can't test multiple immediates at the same time"))
148 `(%test-immediate
,value
,target
,not-p
,(car immediates
)
152 (error "can't test multiple lowtags at the same time"))
154 (error "can't test non-fixnum lowtags and headers at the same time"))
155 `(%test-lowtag
,value
,target
,not-p
,(car lowtags
) ,@other-args
))
157 `(%test-headers
,value
,target
,not-p
,function-p
158 ',(canonicalize-headers headers
)
161 (error "nothing to test?")))))