Better type declarations for fill-pointer related code.
[sbcl.git] / src / compiler / bitops-derive-type.lisp
bloba252cd75ff586710667b1a67d7a3a830406032c7
1 ;;;; This file contains DERIVE-TYPE methods for LOGAND, LOGIOR, and
2 ;;;; friends.
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
13 (in-package "SB!C")
15 ;;; Return the maximum number of bits an integer of the supplied type
16 ;;; can take up, or NIL if it is unbounded. The second (third) value
17 ;;; is T if the integer can be positive (negative) and NIL if not.
18 ;;; Zero counts as positive.
19 (defun integer-type-length (type)
20 (if (numeric-type-p type)
21 (let ((min (numeric-type-low type))
22 (max (numeric-type-high type)))
23 (values (and min max (max (integer-length min) (integer-length max)))
24 (or (null max) (not (minusp max)))
25 (or (null min) (minusp min))))
26 (values nil t t)))
28 ;;;; Generators for simple bit masks
30 ;;; Return an integer consisting of zeroes in its N least significant
31 ;;; bit positions and ones in all others. If N is negative, return -1.
32 (declaim (inline zeroes))
33 (defun zeroes (n)
34 (ash -1 n))
36 ;;; Return an integer consisting of ones in its N least significant
37 ;;; bit positions and zeroes in all others. If N is negative, return 0.
38 (declaim (inline ones))
39 (defun ones (n)
40 (lognot (ash -1 n)))
42 ;;; The functions LOG{AND,IOR,XOR}-DERIVE-UNSIGNED-BOUNDS below use
43 ;;; algorithms derived from those in the chapter "Propagating Bounds
44 ;;; through Logical Operations" from _Hacker's Delight_, Henry S.
45 ;;; Warren, Jr., 2nd ed., pp 87-90.
46 ;;;
47 ;;; We used to implement the algorithms from that source (then its first
48 ;;; edition) very faithfully here which exposed a weakness of theirs,
49 ;;; namely worst case quadratical runtime in the number of bits of the
50 ;;; input values, potentially leading to excessive compilation times for
51 ;;; expressions involving bignums. To avoid that, I have devised and
52 ;;; implemented variations of these algorithms that achieve linear
53 ;;; runtime in all cases.
54 ;;;
55 ;;; Like Warren, let's start with the high bound on LOGIOR to explain
56 ;;; how this is done. To follow, please read Warren's explanations on
57 ;;; his "maxOR" function and compare this with how the second return
58 ;;; value of LOGIOR-DERIVE-UNSIGNED-BOUNDS below is calculated.
59 ;;;
60 ;;; "maxOR" loops starting from the left until it finds a position where
61 ;;; both B and D are 1 and where it is possible to decrease one of these
62 ;;; bounds by setting this bit in it to 0 and all following ones to 1
63 ;;; without the resulting value getting below the corresponding lower
64 ;;; bound (A or C). This is done by calculating the modified values
65 ;;; during each iteration where both B and D are 1 and comparing them
66 ;;; against the lower bounds.
67 ;;; The trick to avoid the loop is to exchange the order of the steps:
68 ;;; First determine from which position rightwards it would be allowed
69 ;;; to change B or D in this way and have the result be larger or equal
70 ;;; than A or C respectively and then find the leftmost position equal
71 ;;; to this or to the right of it where both B and D are 1.
72 ;;; It is quite simple to find from where rightwards B could be modified
73 ;;; this way: This is the leftmost position where B has a 1 and A a 0,
74 ;;; or, cheaper to calculate, the leftmost position where A and B
75 ;;; differ. Thus (INTEGER-LENGTH (LOGXOR A B)) gives us this position
76 ;;; where a result of 1 corresponds to the rightmost bit position. As we
77 ;;; don't care which of B or D we modify we can take the maximum of this
78 ;;; value and of (INTEGER-LENGTH (LOGXOR C D)).
79 ;;; The rest is equally simple: Build a mask of 1 bits from the thusly
80 ;;; found position rightwards, LOGAND it with B and D and feed that into
81 ;;; INTEGER-LENGTH. From this build another mask and LOGIOR it with B
82 ;;; and D to set the desired bits.
83 ;;; The special cases where A equals B and/or C equals D are covered by
84 ;;; the same code provided the mask generator treats an argument of -1
85 ;;; the same as 0, which both ZEROES and ONES do.
86 ;;;
87 ;;; To calculate the low bound on LOGIOR we need to treat X and Y
88 ;;; independently for longer but the basic idea stays the same.
89 ;;;
90 ;;; LOGAND-DERIVE-UNSIGNED-BOUNDS can be derived by sufficiently many
91 ;;; applications of DeMorgan's law from LOGIOR-DERIVE-UNSIGNED-BOUNDS.
92 ;;; The implementation additionally avoids work (that is, calculations
93 ;;; of one's complements) by using the identity (INTEGER-LENGTH X) =
94 ;;; (INTEGER-LENGTH (LOGNOT X)) and observing that ZEROES is cheaper
95 ;;; than ONES.
96 ;;;
97 ;;; For the low bound on LOGXOR we use Warren's formula
98 ;;; minXOR(a, b, c, d) = minAND(a, b, !d, !c) | minAND(!b, !a, c, d)
99 ;;; where "!" is bitwise negation and "|" is bitwise or. Both minANDs
100 ;;; are implemented as in LOGAND-DERIVE-UNSIGNED-BOUNDS (the part for
101 ;;; the first result), sharing the first LOGXOR and INTEGER-LENGTH
102 ;;; calculations as (LOGXOR A B) = (LOGXOR (LOGNOT B) (LOGNOT A)).
104 ;;; For the high bound on LOGXOR Warren's formula seems unnecessarily
105 ;;; complex. Instead, with (LOGNOT (LOGXOR X Y)) = (LOGXOR X (LOGNOT Y))
106 ;;; we have
107 ;;; maxXOR(a, b, c, d) = !minXOR(a, b, !d, !c)
108 ;;; and rewriting minXOR as above yields
109 ;;; maxXOR(a, b, c, d) = !(minAND(a, b, c, d) | minAND(!b, !a, !d, !c))
110 ;;; This again shares the first LOGXOR and INTEGER-LENGTH calculations
111 ;;; between both minANDs and with the ones for the low bound.
113 ;;; LEU, 2013-04-29.
115 (defun logand-derive-unsigned-bounds (x y)
116 (let* ((a (numeric-type-low x))
117 (b (numeric-type-high x))
118 (c (numeric-type-low y))
119 (d (numeric-type-high y))
120 (length-xor-x (integer-length (logxor a b)))
121 (length-xor-y (integer-length (logxor c d))))
122 (values
123 (let* ((mask (zeroes (max length-xor-x length-xor-y)))
124 (index (integer-length (logior mask a c))))
125 (logand a c (zeroes (1- index))))
126 (let* ((mask-x (ones length-xor-x))
127 (mask-y (ones length-xor-y))
128 (index-x (integer-length (logand mask-x b (lognot d))))
129 (index-y (integer-length (logand mask-y d (lognot b)))))
130 (cond ((= index-x index-y)
131 ;; Both indexes are 0 here.
132 (logand b d))
133 ((> index-x index-y)
134 (logand (logior b (ones (1- index-x))) d))
136 (logand (logior d (ones (1- index-y))) b)))))))
138 (defun logand-derive-type-aux (x y &optional same-leaf)
139 (when same-leaf
140 (return-from logand-derive-type-aux x))
141 (multiple-value-bind (x-len x-pos x-neg) (integer-type-length x)
142 (declare (ignore x-pos))
143 (multiple-value-bind (y-len y-pos y-neg) (integer-type-length y)
144 (declare (ignore y-pos))
145 (if (not x-neg)
146 ;; X must be positive.
147 (if (not y-neg)
148 ;; They must both be positive.
149 (cond ((and (null x-len) (null y-len))
150 (specifier-type 'unsigned-byte))
151 ((null x-len)
152 (specifier-type `(unsigned-byte* ,y-len)))
153 ((null y-len)
154 (specifier-type `(unsigned-byte* ,x-len)))
156 (multiple-value-bind (low high)
157 (logand-derive-unsigned-bounds x y)
158 (specifier-type `(integer ,low ,high)))))
159 ;; X is positive, but Y might be negative.
160 (cond ((null x-len)
161 (specifier-type 'unsigned-byte))
163 (specifier-type `(unsigned-byte* ,x-len)))))
164 ;; X might be negative.
165 (if (not y-neg)
166 ;; Y must be positive.
167 (cond ((null y-len)
168 (specifier-type 'unsigned-byte))
169 (t (specifier-type `(unsigned-byte* ,y-len))))
170 ;; Either might be negative.
171 (if (and x-len y-len)
172 ;; The result is bounded.
173 (specifier-type `(signed-byte ,(1+ (max x-len y-len))))
174 ;; We can't tell squat about the result.
175 (specifier-type 'integer)))))))
177 (defun logior-derive-unsigned-bounds (x y)
178 (let* ((a (numeric-type-low x))
179 (b (numeric-type-high x))
180 (c (numeric-type-low y))
181 (d (numeric-type-high y))
182 (length-xor-x (integer-length (logxor a b)))
183 (length-xor-y (integer-length (logxor c d))))
184 (values
185 (let* ((mask-x (ones length-xor-x))
186 (mask-y (ones length-xor-y))
187 (index-x (integer-length (logand mask-x (lognot a) c)))
188 (index-y (integer-length (logand mask-y (lognot c) a))))
189 (cond ((= index-x index-y)
190 ;; Both indexes are 0 here.
191 (logior a c))
192 ((> index-x index-y)
193 (logior (logand a (zeroes (1- index-x))) c))
195 (logior (logand c (zeroes (1- index-y))) a))))
196 (let* ((mask (ones (max length-xor-x length-xor-y)))
197 (index (integer-length (logand mask b d))))
198 (logior b d (ones (1- index)))))))
200 (defun logior-derive-type-aux (x y &optional same-leaf)
201 (when same-leaf
202 (return-from logior-derive-type-aux x))
203 (multiple-value-bind (x-len x-pos x-neg) (integer-type-length x)
204 (multiple-value-bind (y-len y-pos y-neg) (integer-type-length y)
205 (cond
206 ((and (not x-neg) (not y-neg))
207 ;; Both are positive.
208 (if (and x-len y-len)
209 (multiple-value-bind (low high)
210 (logior-derive-unsigned-bounds x y)
211 (specifier-type `(integer ,low ,high)))
212 (specifier-type `(unsigned-byte* *))))
213 ((not x-pos)
214 ;; X must be negative.
215 (if (not y-pos)
216 ;; Both are negative. The result is going to be negative
217 ;; and be the same length or shorter than the smaller.
218 (if (and x-len y-len)
219 ;; It's bounded.
220 (specifier-type `(integer ,(ash -1 (min x-len y-len)) -1))
221 ;; It's unbounded.
222 (specifier-type '(integer * -1)))
223 ;; X is negative, but we don't know about Y. The result
224 ;; will be negative, but no more negative than X.
225 (specifier-type
226 `(integer ,(or (numeric-type-low x) '*)
227 -1))))
229 ;; X might be either positive or negative.
230 (if (not y-pos)
231 ;; But Y is negative. The result will be negative.
232 (specifier-type
233 `(integer ,(or (numeric-type-low y) '*)
234 -1))
235 ;; We don't know squat about either. It won't get any bigger.
236 (if (and x-len y-len)
237 ;; Bounded.
238 (specifier-type `(signed-byte ,(1+ (max x-len y-len))))
239 ;; Unbounded.
240 (specifier-type 'integer))))))))
242 (defun logxor-derive-unsigned-bounds (x y)
243 (let* ((a (numeric-type-low x))
244 (b (numeric-type-high x))
245 (c (numeric-type-low y))
246 (d (numeric-type-high y))
247 (not-b (lognot b))
248 (not-d (lognot d))
249 (length-xor-x (integer-length (logxor a b)))
250 (length-xor-y (integer-length (logxor c d)))
251 (mask (zeroes (max length-xor-x length-xor-y))))
252 (values
253 (let ((index-ad (integer-length (logior mask a not-d)))
254 (index-bc (integer-length (logior mask not-b c))))
255 (logior (logand a not-d (zeroes (1- index-ad)))
256 (logand not-b c (zeroes (1- index-bc)))))
257 (let ((index-ac (integer-length (logior mask a c)))
258 (index-bd (integer-length (logior mask not-b not-d))))
259 (lognor (logand a c (zeroes (1- index-ac)))
260 (logand not-b not-d (zeroes (1- index-bd))))))))
262 (defun logxor-derive-type-aux (x y &optional same-leaf)
263 (when same-leaf
264 (return-from logxor-derive-type-aux (specifier-type '(eql 0))))
265 (multiple-value-bind (x-len x-pos x-neg) (integer-type-length x)
266 (multiple-value-bind (y-len y-pos y-neg) (integer-type-length y)
267 (cond
268 ((and (not x-neg) (not y-neg))
269 ;; Both are positive
270 (if (and x-len y-len)
271 (multiple-value-bind (low high)
272 (logxor-derive-unsigned-bounds x y)
273 (specifier-type `(integer ,low ,high)))
274 (specifier-type '(unsigned-byte* *))))
275 ((and (not x-pos) (not y-pos))
276 ;; Both are negative. The result will be positive, and as long
277 ;; as the longer.
278 (specifier-type `(unsigned-byte* ,(if (and x-len y-len)
279 (max x-len y-len)
280 '*))))
281 ((or (and (not x-pos) (not y-neg))
282 (and (not y-pos) (not x-neg)))
283 ;; Either X is negative and Y is positive or vice-versa. The
284 ;; result will be negative.
285 (specifier-type `(integer ,(if (and x-len y-len)
286 (ash -1 (max x-len y-len))
288 -1)))
289 ;; We can't tell what the sign of the result is going to be.
290 ;; All we know is that we don't create new bits.
291 ((and x-len y-len)
292 (specifier-type `(signed-byte ,(1+ (max x-len y-len)))))
294 (specifier-type 'integer))))))
296 (macrolet ((deffrob (logfun)
297 (let ((fun-aux (symbolicate logfun "-DERIVE-TYPE-AUX")))
298 `(defoptimizer (,logfun derive-type) ((x y))
299 (two-arg-derive-type x y #',fun-aux #',logfun)))))
300 (deffrob logand)
301 (deffrob logior)
302 (deffrob logxor))
304 (defoptimizer (logeqv derive-type) ((x y))
305 (two-arg-derive-type x y (lambda (x y same-leaf)
306 (lognot-derive-type-aux
307 (logxor-derive-type-aux x y same-leaf)))
308 #'logeqv))
309 (defoptimizer (lognand derive-type) ((x y))
310 (two-arg-derive-type x y (lambda (x y same-leaf)
311 (lognot-derive-type-aux
312 (logand-derive-type-aux x y same-leaf)))
313 #'lognand))
314 (defoptimizer (lognor derive-type) ((x y))
315 (two-arg-derive-type x y (lambda (x y same-leaf)
316 (lognot-derive-type-aux
317 (logior-derive-type-aux x y same-leaf)))
318 #'lognor))
319 (defoptimizer (logandc1 derive-type) ((x y))
320 (two-arg-derive-type x y (lambda (x y same-leaf)
321 (if same-leaf
322 (specifier-type '(eql 0))
323 (logand-derive-type-aux
324 (lognot-derive-type-aux x) y)))
325 #'logandc1))
326 (defoptimizer (logandc2 derive-type) ((x y))
327 (two-arg-derive-type x y (lambda (x y same-leaf)
328 (if same-leaf
329 (specifier-type '(eql 0))
330 (logand-derive-type-aux
331 x (lognot-derive-type-aux y))))
332 #'logandc2))
333 (defoptimizer (logorc1 derive-type) ((x y))
334 (two-arg-derive-type x y (lambda (x y same-leaf)
335 (if same-leaf
336 (specifier-type '(eql -1))
337 (logior-derive-type-aux
338 (lognot-derive-type-aux x) y)))
339 #'logorc1))
340 (defoptimizer (logorc2 derive-type) ((x y))
341 (two-arg-derive-type x y (lambda (x y same-leaf)
342 (if same-leaf
343 (specifier-type '(eql -1))
344 (logior-derive-type-aux
345 x (lognot-derive-type-aux y))))
346 #'logorc2))