1 ;;;; type testing and checking VOPs for the ARM VM
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.
14 (defun %test-fixnum
(value target not-p
&key temp
)
15 (declare (ignore temp
))
17 (inst tst value fixnum-tag-mask
)
18 (inst b
(if not-p
:ne
:eq
) target
)))
20 (defun %test-fixnum-immediate-and-headers
(value target not-p immediate
22 (let ((drop-through (gen-label)))
23 (inst tst value fixnum-tag-mask
)
24 (inst b
:eq
(if not-p drop-through target
))
25 (%test-immediate-and-headers value target not-p immediate headers
26 :drop-through drop-through
:temp temp
)))
28 (defun %test-immediate-and-headers
(value target not-p immediate headers
29 &key
(drop-through (gen-label)) temp
)
31 (inst mov temp immediate
)
32 (inst cmp temp
(extend value
:uxtb
))
33 (inst b
:eq
(if not-p drop-through target
))
34 (%test-headers value target not-p nil headers
:drop-through drop-through
37 (defun %test-fixnum-and-headers
(value target not-p headers
&key temp
)
38 (let ((drop-through (gen-label)))
40 (inst ands temp value fixnum-tag-mask
)
41 (inst b
:eq
(if not-p drop-through target
)))
42 (%test-headers value target not-p nil headers
43 :drop-through drop-through
:temp temp
)))
45 (defun %test-immediate
(value target not-p immediate
&key temp
)
47 (inst and temp value widetag-mask
)
48 (inst cmp temp immediate
)
49 (inst b
(if not-p
:ne
:eq
) target
)))
51 (defun %test-lowtag
(value target not-p lowtag
&key temp
)
53 (inst and temp value lowtag-mask
)
54 (inst cmp temp lowtag
)
55 (inst b
(if not-p
:ne
:eq
) target
)))
57 (defun %test-headers
(value target not-p function-p headers
58 &key temp
(drop-through (gen-label)))
59 (let ((lowtag (if function-p fun-pointer-lowtag other-pointer-lowtag
)))
60 (multiple-value-bind (when-true when-false
)
62 (values drop-through target
)
63 (values target drop-through
))
65 (%test-lowtag value when-false t lowtag
:temp temp
)
66 (load-type temp value
(- lowtag
))
67 (do ((remaining headers
(cdr remaining
)))
69 (let ((header (car remaining
))
70 (last (null (cdr remaining
))))
74 ((and (not last
) (null (cddr remaining
))
75 (atom (cadr remaining
))
76 (= (logcount (logxor header
(cadr remaining
))) 1))
77 (inst and temp temp
(logical-mask
78 (ldb (byte 8 0) (logeqv header
(cadr remaining
)))))
79 (inst cmp temp
(ldb (byte 8 0) (logand header
(cadr remaining
))))
80 (inst b
(if not-p
:ne
:eq
) target
)
83 (inst cmp temp header
)
85 (inst b
(if not-p
:ne
:eq
) target
)
86 (inst b
:eq when-true
)))))
88 (let ((start (car header
))
91 ((and last
(not (= start bignum-widetag
))
93 (= (logcount (logxor start end
)) 1))
94 (inst and temp temp
(logical-mask
95 (ldb (byte 8 0) (logeqv start end
))))
96 (inst cmp temp
(ldb (byte 8 0) (logand start end
)))
97 (inst b
(if not-p
:ne
:eq
) target
))
98 ((and (not last
) (null (cddr remaining
))
99 (= (+ start
4) end
) (= (logcount (logxor start end
)) 1)
100 (listp (cadr remaining
))
101 (= (+ (caadr remaining
) 4) (cdadr remaining
))
102 (= (logcount (logxor (caadr remaining
) (cdadr remaining
))) 1)
103 (= (logcount (logxor (caadr remaining
) start
)) 1))
104 (inst and temp temp
(ldb (byte 8 0) (logeqv start
(cdadr remaining
))))
105 (inst cmp temp
(ldb (byte 8 0) (logand start
(cdadr remaining
))))
106 (inst b
(if not-p
:ne
:eq
) target
)
109 (unless (= start bignum-widetag
)
110 (inst cmp temp start
)
111 (if (= end complex-array-widetag
)
114 (inst b
(if not-p
:lt
:ge
) target
))
115 (inst b
:lt when-false
)))
116 (unless (= end complex-array-widetag
)
119 (inst b
(if not-p
:gt
:le
) target
)
120 (inst b
:le when-true
))))))))))
121 (emit-label drop-through
)))))
123 ;;;; Other integer ranges.
125 ;;; A (signed-byte 64) can be represented with either fixnum or a bignum with
126 ;;; exactly one digit.
127 (define-vop (signed-byte-64-p type-predicate
)
128 (:translate signed-byte-64-p
)
130 (multiple-value-bind (yep nope
)
132 (values not-target target
)
133 (values target not-target
))
135 (inst ands temp value fixnum-tag-mask
)
137 (test-type value nope t
(other-pointer-lowtag) :temp temp
)
138 (loadw temp value
0 other-pointer-lowtag
)
139 (inst cmp temp
(+ (ash 1 n-widetag-bits
) bignum-widetag
))
140 (inst b
(if not-p
:ne
:eq
) target
)))
143 ;;; An (UNSIGNED-BYTE 64) can be represented with either a positive
144 ;;; fixnum, a bignum with exactly one positive digit, or a bignum with
145 ;;; exactly two digits and the second digit all zeros.
146 (define-vop (unsigned-byte-64-p type-predicate
)
147 (:translate unsigned-byte-64-p
)
149 (let ((single-word (gen-label))
150 (fixnum (gen-label)))
151 (multiple-value-bind (yep nope
)
153 (values not-target target
)
154 (values target not-target
))
158 (%test-fixnum temp fixnum nil
)
160 ;; If not, is it an other pointer?
161 (test-type value nope t
(other-pointer-lowtag) :temp temp
)
163 (loadw temp value
0 other-pointer-lowtag
)
165 (inst cmp temp
(+ (ash 1 n-widetag-bits
) bignum-widetag
))
166 (inst b
:eq single-word
)
167 ;; If it's other than two, it can't be an (unsigned-byte 64)
168 (inst cmp temp
(+ (ash 2 n-widetag-bits
) bignum-widetag
))
170 ;; Get the second digit.
171 (loadw temp value
(1+ bignum-digits-offset
) other-pointer-lowtag
)
172 ;; All zeros, it's an (unsigned-byte 64).
176 (emit-label single-word
)
177 ;; Get the single digit.
178 (loadw temp value bignum-digits-offset other-pointer-lowtag
)
180 ;; positive implies (unsigned-byte 64).
185 (inst b
:ge target
))))
189 (define-vop (fixnump/unsigned-byte-64
)
191 (:args
(value :scs
(unsigned-reg)))
192 (:arg-types unsigned-num
)
196 (inst tst value
(ash (1- (ash 1 (- n-word-bits
197 n-positive-fixnum-bits
)))
198 n-positive-fixnum-bits
))))
200 (define-vop (fixnump/signed-byte-64 type-predicate
)
201 (:args
(value :scs
(signed-reg)))
204 (:arg-types signed-num
)
207 (inst adds temp value value
)))
210 (defun power-of-two-limit-p (x)
212 (= (logcount (1+ x
)) 1)))
214 (define-vop (test-fixnum-mod-power-of-two)
215 (:args
(value :scs
(any-reg descriptor-reg
216 unsigned-reg signed-reg
219 (:constant
(satisfies power-of-two-limit-p
)))
220 (:translate fixnum-mod-p
)
223 (:save-p
:compute-only
)
226 (aver (not (sc-is value immediate
)))
227 (let* ((fixnum-hi (if (sc-is value unsigned-reg signed-reg
)
230 (inst tst value
(lognot fixnum-hi
)))))
232 (define-vop (test-fixnum-mod-tagged-unsigned-imm)
233 (:args
(value :scs
(any-reg descriptor-reg
234 unsigned-reg signed-reg
236 (:arg-types
(:or tagged-num unsigned-num signed-num
)
237 (:constant
(satisfies add-sub-immediate-p
)))
238 (:translate fixnum-mod-p
)
241 (:save-p
:compute-only
)
244 (aver (not (sc-is value immediate
)))
245 (let ((fixnum-hi (if (sc-is value unsigned-reg signed-reg
)
248 (inst cmp value fixnum-hi
))))
250 (defun add-sub-immediate+1-p
(x)
251 (add-sub-immediate-p (1+ (fixnumize x
))))
253 ;;; Adding 1 and changing the codntions from <= to < allows to encode
255 (define-vop (test-fixnum-mod-tagged-unsigned-imm+1)
256 (:args
(value :scs
(any-reg descriptor-reg
257 unsigned-reg signed-reg
259 (:arg-types
(:or tagged-num unsigned-num signed-num
)
260 (:constant
(satisfies add-sub-immediate
+1-p
)))
261 (:translate fixnum-mod-p
)
264 (:save-p
:compute-only
)
267 (aver (not (sc-is value immediate
)))
268 (let ((fixnum-hi (if (sc-is value unsigned-reg signed-reg
)
270 (fixnumize (1+ hi
)))))
271 (inst cmp value fixnum-hi
))))
273 (define-vop (test-fixnum-mod-tagged-unsigned)
274 (:args
(value :scs
(any-reg descriptor-reg
275 unsigned-reg signed-reg
277 (:arg-types
(:or tagged-num unsigned-num signed-num
)
279 (:temporary
(:scs
(non-descriptor-reg)) temp
)
280 (:translate fixnum-mod-p
)
283 (:save-p
:compute-only
)
286 (aver (not (sc-is value immediate
)))
287 (let ((fixnum-hi (if (sc-is value unsigned-reg signed-reg
)
290 (load-immediate-word temp fixnum-hi
)
291 (inst cmp value temp
))))
293 (defun add-sub-immediate/+1-p
(x)
294 (let ((x (fixnumize x
)))
295 (or (add-sub-immediate-p x
)
296 (add-sub-immediate-p (1+ x
)))))
298 (define-vop (test-fixnum-mod-*-imm
)
299 (:args
(value :scs
(any-reg descriptor-reg
)))
300 (:arg-types
* (:constant
(satisfies add-sub-immediate
/+1-p
)))
301 (:translate fixnum-mod-p
)
303 (:info target not-p hi
)
304 (:save-p
:compute-only
)
307 (let* ((1+ (not (add-sub-immediate-p (fixnumize hi
))))
308 (fixnum-hi (fixnumize (if 1+
311 #.
(assert (= fixnum-tag-mask
1))
313 (inst tst value fixnum-tag-mask
)
314 ;; TBNZ can't jump as far as B.
317 (inst tbnz value
0 skip
)))
318 (inst cmp value fixnum-hi
)
325 (define-vop (test-fixnum-mod-*)
326 (:args
(value :scs
(any-reg descriptor-reg
)))
327 (:arg-types
* (:constant fixnum
))
328 (:translate fixnum-mod-p
)
329 (:temporary
(:scs
(any-reg)) temp
)
331 (:info target not-p hi
)
332 (:save-p
:compute-only
)
335 #.
(assert (= fixnum-tag-mask
1))
337 (inst tst value fixnum-tag-mask
)
338 ;; TBNZ can't jump as far as B.
341 (inst tbnz value
0 skip
)))
342 (let ((condition (if not-p
:hi
:ls
)))
343 (load-immediate-word temp
(fixnumize hi
))
344 (inst cmp value temp
)
345 (inst b condition target
))
348 ;;;; List/symbol types:
350 ;;; symbolp (or symbol (eq nil))
351 ;;; consp (and list (not (eq nil)))
353 (define-vop (symbolp type-predicate
)
356 (let* ((drop-thru (gen-label))
357 (is-symbol-label (if not-p drop-thru target
)))
358 (inst cmp value null-tn
)
359 (inst b
:eq is-symbol-label
)
360 (test-type value target not-p
(symbol-widetag) :temp temp
)
361 (emit-label drop-thru
))))
363 (define-vop (consp type-predicate
)
366 (let* ((drop-thru (gen-label))
367 (is-not-cons-label (if not-p target drop-thru
)))
368 (inst cmp value null-tn
)
369 (inst b
:eq is-not-cons-label
)
370 (test-type value target not-p
(list-pointer-lowtag) :temp temp
)
371 (emit-label drop-thru
))))