Handle (aref v (+ i k)), with i negative
[sbcl.git] / src / compiler / generic / vm-tran.lisp
1 ;;;; implementation-dependent transforms
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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.
11
12 (in-package "SB!C")
13
14 ;;; We need to define these predicates, since the TYPEP source
15 ;;; transform picks whichever predicate was defined last when there
16 ;;; are multiple predicates for equivalent types.
17 (define-source-transform short-float-p (x) `(single-float-p ,x))
18 #!-long-float
19 (define-source-transform long-float-p (x) `(double-float-p ,x))
20
21 (define-source-transform compiled-function-p (x)
22   #!-sb-eval
23   `(functionp ,x)
24   #!+sb-eval
25   (once-only ((x x))
26     `(and (functionp ,x)
27           (not (sb!eval:interpreted-function-p ,x)))))
28
29 (define-source-transform char-int (x)
30   `(char-code ,x))
31
32 (deftransform abs ((x) (rational))
33   '(if (< x 0) (- x) x))
34
35 ;;; We don't want to clutter the bignum code.
36 #!+(or x86 x86-64)
37 (define-source-transform sb!bignum:%bignum-ref (bignum index)
38   ;; KLUDGE: We use TRULY-THE here because even though the bignum code
39   ;; is (currently) compiled with (SAFETY 0), the compiler insists on
40   ;; inserting CAST nodes to ensure that INDEX is of the correct type.
41   ;; These CAST nodes do not generate any type checks, but they do
42   ;; interfere with the operation of FOLD-INDEX-ADDRESSING, below.
43   ;; This scenario is a problem for the more user-visible case of
44   ;; folding as well.  --njf, 2006-12-01
45   `(sb!bignum:%bignum-ref-with-offset ,bignum
46                                       (truly-the bignum-index ,index) 0))
47
48 #!+(or x86 x86-64)
49 (defun fold-index-addressing (fun-name element-size lowtag data-offset
50                               index offset &optional setter-p)
51   (multiple-value-bind (func index-args) (extract-fun-args index '(+ -) 2)
52     (destructuring-bind (x constant) index-args
53       (unless (and (constant-lvar-p constant)
54                    ;; we lose if the remaining argument isn't a fixnum
55                    (csubtypep (lvar-type x) (specifier-type 'fixnum)))
56         (give-up-ir1-transform))
57       (let ((value (lvar-value constant))
58             new-offset)
59         (unless (and (integerp value)
60                      (sb!vm::foldable-constant-offset-p
61                       element-size lowtag data-offset
62                       (setf new-offset (funcall func (lvar-value offset)
63                                                 value))))
64           (give-up-ir1-transform "constant is too large for inlining"))
65         (splice-fun-args index func 2)
66         `(lambda (thing index off1 off2 ,@(when setter-p
67                                             '(value)))
68            (declare (ignore off1 off2))
69            (,fun-name thing index ',new-offset ,@(when setter-p
70                                                    '(value))))))))
71
72 #!+(or x86 x86-64)
73 (deftransform sb!bignum:%bignum-ref-with-offset
74     ((bignum index offset) * * :node node)
75   (fold-index-addressing 'sb!bignum:%bignum-ref-with-offset
76                          sb!vm:n-word-bits sb!vm:other-pointer-lowtag
77                          sb!vm:bignum-digits-offset
78                          index offset))
79
80 ;;; The layout is stored in slot 0.
81 (define-source-transform %instance-layout (x)
82   `(truly-the layout (%instance-ref ,x 0)))
83 (define-source-transform %set-instance-layout (x val)
84   `(%instance-set ,x 0 (the layout ,val)))
85 (define-source-transform %funcallable-instance-layout (x)
86   `(truly-the layout (%funcallable-instance-info ,x 0)))
87 (define-source-transform %set-funcallable-instance-layout (x val)
88   `(setf (%funcallable-instance-info ,x 0) (the layout ,val)))
89 \f
90 ;;;; character support
91
92 ;;; In our implementation there are really only BASE-CHARs.
93 #+nil
94 (define-source-transform characterp (obj)
95   `(base-char-p ,obj))
96 \f
97 ;;;; simplifying HAIRY-DATA-VECTOR-REF and HAIRY-DATA-VECTOR-SET
98
99 (deftransform hairy-data-vector-ref ((string index) (simple-string t))
100   (let ((ctype (lvar-type string)))
101     (if (array-type-p ctype)
102         ;; the other transform will kick in, so that's OK
103         (give-up-ir1-transform)
104         `(etypecase string
105           ((simple-array character (*))
106            (data-vector-ref string index))
107           #!+sb-unicode
108           ((simple-array base-char (*))
109            (data-vector-ref string index))
110           ((simple-array nil (*))
111            (data-vector-ref string index))))))
112
113 ;;; This and the corresponding -SET transform work equally well on non-simple
114 ;;; arrays, but after benchmarking (on x86), Nikodemus didn't find any cases
115 ;;; where it actually helped with non-simple arrays -- to the contrary, it
116 ;;; only made for bigger and up to 100% slower code.
117 (deftransform hairy-data-vector-ref ((array index) (simple-array t) *)
118   "avoid runtime dispatch on array element type"
119   (let* ((type (lvar-type array))
120          (element-ctype (array-type-upgraded-element-type type))
121          (declared-element-ctype (array-type-declared-element-type type)))
122     (declare (type ctype element-ctype))
123     (when (eq *wild-type* element-ctype)
124       (give-up-ir1-transform
125        "Upgraded element type of array is not known at compile time."))
126     ;; (The expansion here is basically a degenerate case of
127     ;; WITH-ARRAY-DATA. Since WITH-ARRAY-DATA is implemented as a
128     ;; macro, and macros aren't expanded in transform output, we have
129     ;; to hand-expand it ourselves.)
130     (let* ((element-type-specifier (type-specifier element-ctype)))
131       `(multiple-value-bind (array index)
132            (%data-vector-and-index array index)
133          (declare (type (simple-array ,element-type-specifier 1) array))
134          ,(let ((bare-form '(data-vector-ref array index)))
135             (if (type= element-ctype declared-element-ctype)
136                 bare-form
137                 `(the ,(type-specifier declared-element-ctype)
138                       ,bare-form)))))))
139
140 ;;; Transform multi-dimensional array to one dimensional data vector
141 ;;; access.
142 (deftransform data-vector-ref ((array index) (simple-array t))
143   (let ((array-type (lvar-type array)))
144     (unless (array-type-p array-type)
145       (give-up-ir1-transform))
146     (let ((dims (array-type-dimensions array-type)))
147       (when (or (atom dims) (= (length dims) 1))
148         (give-up-ir1-transform))
149       (let ((el-type (array-type-specialized-element-type array-type))
150             (total-size (if (member '* dims)
151                             '*
152                             (reduce #'* dims))))
153         `(data-vector-ref (truly-the (simple-array ,(type-specifier el-type)
154                                                    (,total-size))
155                                      (%array-data-vector array))
156                           index)))))
157
158 ;;; Transform data vector access to a form that opens up optimization
159 ;;; opportunities. On platforms that support DATA-VECTOR-REF-WITH-OFFSET
160 ;;; DATA-VECTOR-REF is not supported at all.
161 #!+(or x86 x86-64)
162 (define-source-transform data-vector-ref (array index)
163   `(data-vector-ref-with-offset ,array ,index 0))
164
165 #!+(or x86 x86-64)
166 (deftransform data-vector-ref-with-offset ((array index offset))
167   (let ((array-type (lvar-type array)))
168     (when (or (not (array-type-p array-type))
169               (eql (array-type-specialized-element-type array-type)
170                    *wild-type*))
171       (give-up-ir1-transform))
172     ;; It shouldn't be possible to get here with anything but a non-complex
173     ;; vector.
174     (aver (not (array-type-complexp array-type)))
175     (let* ((element-type (type-specifier (array-type-specialized-element-type array-type)))
176            (saetp (find-saetp element-type)))
177       (when (< (sb!vm:saetp-n-bits saetp) sb!vm:n-byte-bits)
178         (give-up-ir1-transform))
179       (fold-index-addressing 'data-vector-ref-with-offset
180                              (sb!vm:saetp-n-bits saetp)
181                              sb!vm:other-pointer-lowtag
182                              sb!vm:vector-data-offset
183                              index offset))))
184
185 (deftransform hairy-data-vector-set ((string index new-value)
186                                      (simple-string t t))
187   (let ((ctype (lvar-type string)))
188     (if (array-type-p ctype)
189         ;; the other transform will kick in, so that's OK
190         (give-up-ir1-transform)
191         `(etypecase string
192           ((simple-array character (*))
193            (data-vector-set string index new-value))
194           #!+sb-unicode
195           ((simple-array base-char (*))
196            (data-vector-set string index new-value))
197           ((simple-array nil (*))
198            (data-vector-set string index new-value))))))
199
200 ;;; This and the corresponding -REF transform work equally well on non-simple
201 ;;; arrays, but after benchmarking (on x86), Nikodemus didn't find any cases
202 ;;; where it actually helped with non-simple arrays -- to the contrary, it
203 ;;; only made for bigger and up 1o 100% slower code.
204 (deftransform hairy-data-vector-set ((array index new-value)
205                                      (simple-array t t)
206                                      *)
207   "avoid runtime dispatch on array element type"
208   (let* ((type (lvar-type array))
209          (element-ctype (array-type-upgraded-element-type type))
210          (declared-element-ctype (array-type-declared-element-type type)))
211     (declare (type ctype element-ctype))
212     (when (eq *wild-type* element-ctype)
213       (give-up-ir1-transform
214        "Upgraded element type of array is not known at compile time."))
215     (let ((element-type-specifier (type-specifier element-ctype)))
216       `(multiple-value-bind (array index)
217            (%data-vector-and-index array index)
218          (declare (type (simple-array ,element-type-specifier 1) array)
219                   (type ,element-type-specifier new-value))
220          ,(if (type= element-ctype declared-element-ctype)
221               '(data-vector-set array index new-value)
222               `(truly-the ,(type-specifier declared-element-ctype)
223                  (data-vector-set array index
224                   (the ,(type-specifier declared-element-ctype)
225                        new-value))))))))
226
227 ;;; Transform multi-dimensional array to one dimensional data vector
228 ;;; access.
229 (deftransform data-vector-set ((array index new-value)
230                                (simple-array t t))
231   (let ((array-type (lvar-type array)))
232     (unless (array-type-p array-type)
233       (give-up-ir1-transform))
234     (let ((dims (array-type-dimensions array-type)))
235       (when (or (atom dims) (= (length dims) 1))
236         (give-up-ir1-transform))
237       (let ((el-type (array-type-specialized-element-type array-type))
238             (total-size (if (member '* dims)
239                             '*
240                             (reduce #'* dims))))
241         `(data-vector-set (truly-the (simple-array ,(type-specifier el-type)
242                                                    (,total-size))
243                                      (%array-data-vector array))
244                           index
245                           new-value)))))
246
247 ;;; Transform data vector access to a form that opens up optimization
248 ;;; opportunities.
249 #!+(or x86 x86-64)
250 (define-source-transform data-vector-set (array index new-value)
251   `(data-vector-set-with-offset ,array ,index 0 ,new-value))
252
253 #!+(or x86 x86-64)
254 (deftransform data-vector-set-with-offset ((array index offset new-value))
255   (let ((array-type (lvar-type array)))
256     (when (or (not (array-type-p array-type))
257               (eql (array-type-specialized-element-type array-type)
258                    *wild-type*))
259       ;; We don't yet know the exact element type, but will get that
260       ;; knowledge after some more type propagation.
261       (give-up-ir1-transform))
262     (aver (not (array-type-complexp array-type)))
263     (let* ((element-type (type-specifier (array-type-specialized-element-type array-type)))
264            (saetp (find-saetp element-type)))
265       (when (< (sb!vm:saetp-n-bits saetp) sb!vm:n-byte-bits)
266         (give-up-ir1-transform))
267       (fold-index-addressing 'data-vector-set-with-offset
268                              (sb!vm:saetp-n-bits saetp)
269                              sb!vm:other-pointer-lowtag
270                              sb!vm:vector-data-offset
271                              index offset t))))
272
273 (defun maybe-array-data-vector-type-specifier (array-lvar)
274   (let ((atype (lvar-type array-lvar)))
275     (when (array-type-p atype)
276       (let ((dims (array-type-dimensions atype)))
277         (if (or (array-type-complexp atype)
278                 (eq '* dims)
279                 (notevery #'integerp dims))
280            `(simple-array ,(type-specifier
281                             (array-type-specialized-element-type atype))
282                           (*))
283            `(simple-array ,(type-specifier
284                             (array-type-specialized-element-type atype))
285                           (,(apply #'* dims))))))))
286
287 (macrolet ((def (name)
288              `(defoptimizer (,name derive-type) ((array-lvar))
289                 (let ((spec (maybe-array-data-vector-type-specifier array-lvar)))
290                   (when spec
291                     (specifier-type spec))))))
292   (def %array-data-vector)
293   (def array-storage-vector))
294
295 (defoptimizer (%data-vector-and-index derive-type) ((array index))
296   (let ((spec (maybe-array-data-vector-type-specifier array)))
297     (when spec
298       (values-specifier-type `(values ,spec index)))))
299
300 (deftransform %data-vector-and-index ((%array %index)
301                                       (simple-array t)
302                                       *)
303   ;; KLUDGE: why the percent signs?  Well, ARRAY and INDEX are
304   ;; respectively exported from the CL and SB!INT packages, which
305   ;; means that they're visible to all sorts of things.  If the
306   ;; compiler can prove that the call to ARRAY-HEADER-P, below, either
307   ;; returns T or NIL, it will delete the irrelevant branch.  However,
308   ;; user code might have got here with a variable named CL:ARRAY, and
309   ;; quite often compiler code with a variable named SB!INT:INDEX, so
310   ;; this can generate code deletion notes for innocuous user code:
311   ;; (DEFUN F (ARRAY I) (DECLARE (SIMPLE-VECTOR ARRAY)) (AREF ARRAY I))
312   ;; -- CSR, 2003-04-01
313
314   ;; We do this solely for the -OR-GIVE-UP side effect, since we want
315   ;; to know that the type can be figured out in the end before we
316   ;; proceed, but we don't care yet what the type will turn out to be.
317   (upgraded-element-type-specifier-or-give-up %array)
318
319   '(if (array-header-p %array)
320        (values (%array-data-vector %array) %index)
321        (values %array %index)))
322 \f
323 ;;;; BIT-VECTOR hackery
324
325 ;;; SIMPLE-BIT-VECTOR bit-array operations are transformed to a word
326 ;;; loop that does 32 bits at a time.
327 ;;;
328 ;;; FIXME: This is a lot of repeatedly macroexpanded code. It should
329 ;;; be a function call instead.
330 (macrolet ((def (bitfun wordfun)
331              `(deftransform ,bitfun ((bit-array-1 bit-array-2 result-bit-array)
332                                      (simple-bit-vector
333                                       simple-bit-vector
334                                       simple-bit-vector)
335                                      *
336                                      :node node :policy (>= speed space))
337                 `(progn
338                    ,@(unless (policy node (zerop safety))
339                              '((unless (= (length bit-array-1)
340                                           (length bit-array-2)
341                                           (length result-bit-array))
342                                  (error "Argument and/or result bit arrays are not the same length:~
343                          ~%  ~S~%  ~S  ~%  ~S"
344                                         bit-array-1
345                                         bit-array-2
346                                         result-bit-array))))
347                   (let ((length (length result-bit-array)))
348                     (if (= length 0)
349                         ;; We avoid doing anything to 0-length
350                         ;; bit-vectors, or rather, the memory that
351                         ;; follows them. Other divisible-by-32 cases
352                         ;; are handled by the (1- length), below.
353                         ;; CSR, 2002-04-24
354                         result-bit-array
355                         (do ((index 0 (1+ index))
356                              ;; bit-vectors of length 1-32 need
357                              ;; precisely one (SETF %VECTOR-RAW-BITS),
358                              ;; done here in the epilogue. - CSR,
359                              ;; 2002-04-24
360                              (end-1 (truncate (truly-the index (1- length))
361                                               sb!vm:n-word-bits)))
362                             ((>= index end-1)
363                              (setf (%vector-raw-bits result-bit-array index)
364                                    (,',wordfun (%vector-raw-bits bit-array-1 index)
365                                                (%vector-raw-bits bit-array-2 index)))
366                              result-bit-array)
367                           (declare (optimize (speed 3) (safety 0))
368                                    (type index index end-1))
369                           (setf (%vector-raw-bits result-bit-array index)
370                                 (,',wordfun (%vector-raw-bits bit-array-1 index)
371                                             (%vector-raw-bits bit-array-2 index))))))))))
372  (def bit-and word-logical-and)
373  (def bit-ior word-logical-or)
374  (def bit-xor word-logical-xor)
375  (def bit-eqv word-logical-eqv)
376  (def bit-nand word-logical-nand)
377  (def bit-nor word-logical-nor)
378  (def bit-andc1 word-logical-andc1)
379  (def bit-andc2 word-logical-andc2)
380  (def bit-orc1 word-logical-orc1)
381  (def bit-orc2 word-logical-orc2))
382
383 (deftransform bit-not
384               ((bit-array result-bit-array)
385                (simple-bit-vector simple-bit-vector) *
386                :node node :policy (>= speed space))
387   `(progn
388      ,@(unless (policy node (zerop safety))
389          '((unless (= (length bit-array)
390                       (length result-bit-array))
391              (error "Argument and result bit arrays are not the same length:~
392                      ~%  ~S~%  ~S"
393                     bit-array result-bit-array))))
394     (let ((length (length result-bit-array)))
395       (if (= length 0)
396           ;; We avoid doing anything to 0-length bit-vectors, or rather,
397           ;; the memory that follows them. Other divisible-by
398           ;; n-word-bits cases are handled by the (1- length), below.
399           ;; CSR, 2002-04-24
400           result-bit-array
401           (do ((index 0 (1+ index))
402                ;; bit-vectors of length 1 to n-word-bits need precisely
403                ;; one (SETF %VECTOR-RAW-BITS), done here in the
404                ;; epilogue. - CSR, 2002-04-24
405                (end-1 (truncate (truly-the index (1- length))
406                                 sb!vm:n-word-bits)))
407               ((>= index end-1)
408                (setf (%vector-raw-bits result-bit-array index)
409                      (word-logical-not (%vector-raw-bits bit-array index)))
410                result-bit-array)
411             (declare (optimize (speed 3) (safety 0))
412                      (type index index end-1))
413             (setf (%vector-raw-bits result-bit-array index)
414                   (word-logical-not (%vector-raw-bits bit-array index))))))))
415
416 (deftransform bit-vector-= ((x y) (simple-bit-vector simple-bit-vector))
417   `(and (= (length x) (length y))
418         (let ((length (length x)))
419           (or (= length 0)
420               (do* ((i 0 (+ i 1))
421                     (end-1 (floor (1- length) sb!vm:n-word-bits)))
422                    ((>= i end-1)
423                     (let* ((extra (1+ (mod (1- length) sb!vm:n-word-bits)))
424                            (mask (ash #.(1- (ash 1 sb!vm:n-word-bits))
425                                       (- extra sb!vm:n-word-bits)))
426                            (numx
427                             (logand
428                              (ash mask
429                                   ,(ecase sb!c:*backend-byte-order*
430                                      (:little-endian 0)
431                                      (:big-endian
432                                       '(- sb!vm:n-word-bits extra))))
433                              (%vector-raw-bits x i)))
434                            (numy
435                             (logand
436                              (ash mask
437                                   ,(ecase sb!c:*backend-byte-order*
438                                      (:little-endian 0)
439                                      (:big-endian
440                                       '(- sb!vm:n-word-bits extra))))
441                              (%vector-raw-bits y i))))
442                       (declare (type (integer 1 #.sb!vm:n-word-bits) extra)
443                                (type sb!vm:word mask numx numy))
444                       (= numx numy)))
445                 (declare (type index i end-1))
446                 (let ((numx (%vector-raw-bits x i))
447                       (numy (%vector-raw-bits y i)))
448                   (declare (type sb!vm:word numx numy))
449                   (unless (= numx numy)
450                     (return nil))))))))
451
452 (deftransform count ((item sequence) (bit simple-bit-vector) *
453                      :policy (>= speed space))
454   `(let ((length (length sequence)))
455     (if (zerop length)
456         0
457         (do ((index 0 (1+ index))
458              (count 0)
459              (end-1 (truncate (truly-the index (1- length))
460                               sb!vm:n-word-bits)))
461             ((>= index end-1)
462              (let* ((extra (1+ (mod (1- length) sb!vm:n-word-bits)))
463                     (mask (ash #.(1- (ash 1 sb!vm:n-word-bits))
464                                (- extra sb!vm:n-word-bits)))
465                     (bits (logand (ash mask
466                                        ,(ecase sb!c:*backend-byte-order*
467                                                (:little-endian 0)
468                                                (:big-endian
469                                                 '(- sb!vm:n-word-bits extra))))
470                                   (%vector-raw-bits sequence index))))
471                (declare (type (integer 1 #.sb!vm:n-word-bits) extra))
472                (declare (type sb!vm:word mask bits))
473                (incf count (logcount bits))
474                ,(if (constant-lvar-p item)
475                     (if (zerop (lvar-value item))
476                         '(- length count)
477                         'count)
478                     '(if (zerop item)
479                          (- length count)
480                          count))))
481           (declare (type index index count end-1)
482                    (optimize (speed 3) (safety 0)))
483           (incf count (logcount (%vector-raw-bits sequence index)))))))
484
485 (deftransform fill ((sequence item) (simple-bit-vector bit) *
486                     :policy (>= speed space))
487   (let ((value (if (constant-lvar-p item)
488                    (if (= (lvar-value item) 0)
489                        0
490                        #.(1- (ash 1 sb!vm:n-word-bits)))
491                    `(if (= item 0) 0 #.(1- (ash 1 sb!vm:n-word-bits))))))
492     `(let ((length (length sequence))
493            (value ,value))
494        (if (= length 0)
495            sequence
496            (do ((index 0 (1+ index))
497                 ;; bit-vectors of length 1 to n-word-bits need precisely
498                 ;; one (SETF %VECTOR-RAW-BITS), done here in the
499                 ;; epilogue. - CSR, 2002-04-24
500                 (end-1 (truncate (truly-the index (1- length))
501                                  sb!vm:n-word-bits)))
502                ((>= index end-1)
503                 (setf (%vector-raw-bits sequence index) value)
504                 sequence)
505              (declare (optimize (speed 3) (safety 0))
506                       (type index index end-1))
507              (setf (%vector-raw-bits sequence index) value))))))
508
509 (deftransform fill ((sequence item) (simple-base-string base-char) *
510                     :policy (>= speed space))
511   (let ((value (if (constant-lvar-p item)
512                    (let* ((char (lvar-value item))
513                           (code (sb!xc:char-code char))
514                           (accum 0))
515                      (dotimes (i sb!vm:n-word-bytes accum)
516                        (setf accum (logior accum (ash code (* 8 i))))))
517                    `(let ((code (sb!xc:char-code item)))
518                      (logior ,@(loop for i from 0 below sb!vm:n-word-bytes
519                                      collect `(ash code ,(* 8 i))))))))
520     `(let ((length (length sequence))
521            (value ,value))
522       (multiple-value-bind (times rem)
523           (truncate length sb!vm:n-word-bytes)
524         (do ((index 0 (1+ index))
525              (end times))
526             ((>= index end)
527              (let ((place (* times sb!vm:n-word-bytes)))
528                (declare (fixnum place))
529                (dotimes (j rem sequence)
530                  (declare (index j))
531                  (setf (schar sequence (the index (+ place j))) item))))
532           (declare (optimize (speed 3) (safety 0))
533                    (type index index))
534           (setf (%vector-raw-bits sequence index) value))))))
535 \f
536 ;;;; %BYTE-BLT
537
538 ;;; FIXME: The old CMU CL code used various COPY-TO/FROM-SYSTEM-AREA
539 ;;; stuff (with all the associated bit-index cruft and overflow
540 ;;; issues) even for byte moves. In SBCL, we're converting to byte
541 ;;; moves as problems are discovered with the old code, and this is
542 ;;; currently (ca. sbcl-0.6.12.30) the main interface for code in
543 ;;; SB!KERNEL and SB!SYS (e.g. i/o code). It's not clear that it's the
544 ;;; ideal interface, though, and it probably deserves some thought.
545 (deftransform %byte-blt ((src src-start dst dst-start dst-end)
546                          ((or (simple-unboxed-array (*)) system-area-pointer)
547                           index
548                           (or (simple-unboxed-array (*)) system-area-pointer)
549                           index
550                           index))
551   ;; FIXME: CMU CL had a hairier implementation of this (back when it
552   ;; was still called (%PRIMITIVE BYTE-BLT). It had the small problem
553   ;; that it didn't work for large (>16M) values of SRC-START or
554   ;; DST-START. However, it might have been more efficient. In
555   ;; particular, I don't really know how much the foreign function
556   ;; call costs us here. My guess is that if the overhead is
557   ;; acceptable for SQRT and COS, it's acceptable here, but this
558   ;; should probably be checked. -- WHN
559   '(flet ((sapify (thing)
560             (etypecase thing
561               (system-area-pointer thing)
562               ;; FIXME: The code here rather relies on the simple
563               ;; unboxed array here having byte-sized entries. That
564               ;; should be asserted explicitly, I just haven't found
565               ;; a concise way of doing it. (It would be nice to
566               ;; declare it in the DEFKNOWN too.)
567               ((simple-unboxed-array (*)) (vector-sap thing)))))
568      (declare (inline sapify))
569     (with-pinned-objects (dst src)
570       (memmove (sap+ (sapify dst) dst-start)
571                (sap+ (sapify src) src-start)
572                (- dst-end dst-start)))
573      (values)))
574 \f
575 ;;;; transforms for EQL of floating point values
576 #!-float-eql-vops
577 (deftransform eql ((x y) (single-float single-float))
578   '(= (single-float-bits x) (single-float-bits y)))
579
580 #!-float-eql-vops
581 (deftransform eql ((x y) (double-float double-float))
582   '(and (= (double-float-low-bits x) (double-float-low-bits y))
583         (= (double-float-high-bits x) (double-float-high-bits y))))
584
585 \f
586 ;;;; modular functions
587 ;;;
588 ;;; FIXME: I think that the :GOODness of a modular function boils down
589 ;;; to whether the normal definition can be used in the middle of a
590 ;;; modular arrangement.  LOGAND and LOGIOR can be for all unsigned
591 ;;; modular implementations, I believe, because for all unsigned
592 ;;; arguments of a given size the result of the ordinary definition is
593 ;;; the right one.  This should follow through to other logical
594 ;;; functions, such as LOGXOR, should it not?  -- CSR, 2007-12-29,
595 ;;; trying to understand a comment he wrote over four years
596 ;;; previously: "FIXME: XOR? ANDC1, ANDC2?  -- CSR, 2003-09-16"
597 (define-good-modular-fun logand :untagged nil)
598 (define-good-modular-fun logior :untagged nil)
599 (define-good-modular-fun logxor :untagged nil)
600 (macrolet ((define-good-signed-modular-funs (&rest funs)
601              (let (result)
602                `(progn
603                  ,@(dolist (fun funs (nreverse result))
604                      (push `(define-good-modular-fun ,fun :untagged t) result)
605                      (push `(define-good-modular-fun ,fun :tagged t) result))))))
606   (define-good-signed-modular-funs
607       logand logandc1 logandc2 logeqv logior lognand lognor lognot
608       logorc1 logorc2 logxor))
609
610 (macrolet
611     ((def (name kind width signedp)
612        (let ((type (ecase signedp
613                      ((nil) 'unsigned-byte)
614                      ((t) 'signed-byte))))
615          `(progn
616             (defknown ,name (integer (integer 0)) (,type ,width)
617                       (foldable flushable movable))
618             (define-modular-fun-optimizer ash ((integer count) ,kind ,signedp :width width)
619               (when (and (<= width ,width)
620                          (or (and (constant-lvar-p count)
621                                   (plusp (lvar-value count)))
622                              (csubtypep (lvar-type count)
623                                         (specifier-type '(and unsigned-byte fixnum)))))
624                 (cut-to-width integer ,kind width ,signedp)
625                 ',name))
626             (setf (gethash ',name (modular-class-versions (find-modular-class ',kind ',signedp)))
627                   `(ash ,',width))))))
628   ;; This should really be dependent on SB!VM:N-WORD-BITS, but since we
629   ;; don't have a true Alpha64 port yet, we'll have to stick to
630   ;; SB!VM:N-MACHINE-WORD-BITS for the time being.  --njf, 2004-08-14
631   #.`(progn
632        #!+(or x86 x86-64)
633        (def sb!vm::ash-left-modfx
634            :tagged ,(- sb!vm:n-word-bits sb!vm:n-fixnum-tag-bits) t)
635        (def ,(intern (format nil "ASH-LEFT-MOD~D" sb!vm:n-machine-word-bits)
636                      "SB!VM")
637            :untagged ,sb!vm:n-machine-word-bits nil)))
638 \f
639 ;;;; word-wise logical operations
640
641 ;;; These transforms assume the presence of modular arithmetic to
642 ;;; generate efficient code.
643
644 (define-source-transform word-logical-not (x)
645   `(logand (lognot (the sb!vm:word ,x)) #.(1- (ash 1 sb!vm:n-word-bits))))
646
647 (deftransform word-logical-and ((x y))
648   '(logand x y))
649
650 (deftransform word-logical-nand ((x y))
651   '(logand (lognand x y) #.(1- (ash 1 sb!vm:n-word-bits))))
652
653 (deftransform word-logical-or ((x y))
654   '(logior x y))
655
656 (deftransform word-logical-nor ((x y))
657   '(logand (lognor x y) #.(1- (ash 1 sb!vm:n-word-bits))))
658
659 (deftransform word-logical-xor ((x y))
660   '(logxor x y))
661
662 (deftransform word-logical-eqv ((x y))
663   '(logand (logeqv x y) #.(1- (ash 1 sb!vm:n-word-bits))))
664
665 (deftransform word-logical-orc1 ((x y))
666   '(logand (logorc1 x y) #.(1- (ash 1 sb!vm:n-word-bits))))
667
668 (deftransform word-logical-orc2 ((x y))
669   '(logand (logorc2 x y) #.(1- (ash 1 sb!vm:n-word-bits))))
670
671 (deftransform word-logical-andc1 ((x y))
672   '(logand (logandc1 x y) #.(1- (ash 1 sb!vm:n-word-bits))))
673
674 (deftransform word-logical-andc2 ((x y))
675   '(logand (logandc2 x y) #.(1- (ash 1 sb!vm:n-word-bits))))
676
677 \f
678 ;;; There are two different ways the multiplier can be recoded. The
679 ;;; more obvious is to shift X by the correct amount for each bit set
680 ;;; in Y and to sum the results. But if there is a string of bits that
681 ;;; are all set, you can add X shifted by one more then the bit
682 ;;; position of the first set bit and subtract X shifted by the bit
683 ;;; position of the last set bit. We can't use this second method when
684 ;;; the high order bit is bit 31 because shifting by 32 doesn't work
685 ;;; too well.
686 (defun ub32-strength-reduce-constant-multiply (arg num)
687   (declare (type (unsigned-byte 32) num))
688   (let ((adds 0) (shifts 0)
689         (result nil) first-one)
690     (labels ((add (next-factor)
691                (setf result
692                      (if result
693                          (progn (incf adds) `(+ ,result ,next-factor))
694                          next-factor))))
695       (declare (inline add))
696       (dotimes (bitpos 32)
697         (if first-one
698             (when (not (logbitp bitpos num))
699               (add (if (= (1+ first-one) bitpos)
700                        ;; There is only a single bit in the string.
701                        (progn (incf shifts) `(ash ,arg ,first-one))
702                        ;; There are at least two.
703                        (progn
704                          (incf adds)
705                          (incf shifts 2)
706                          `(- (ash ,arg ,bitpos)
707                              (ash ,arg ,first-one)))))
708               (setf first-one nil))
709             (when (logbitp bitpos num)
710               (setf first-one bitpos))))
711       (when first-one
712         (cond ((= first-one 31))
713               ((= first-one 30) (incf shifts) (add `(ash ,arg 30)))
714               (t
715                (incf shifts 2)
716                (incf adds)
717                (add `(- (ash ,arg 31)
718                         (ash ,arg ,first-one)))))
719         (incf shifts)
720         (add `(ash ,arg 31))))
721     (values (if (plusp adds)
722                 `(logand ,result #.(1- (ash 1 32))) ; using modular arithmetic
723                 result)
724             adds
725             shifts)))
726
727 \f
728 ;;; Transform GET-LISP-OBJ-ADDRESS for constant immediates, since the normal
729 ;;; VOP can't handle them.
730
731 (deftransform sb!vm::get-lisp-obj-address ((obj) ((constant-arg fixnum)))
732   (ash (lvar-value obj) sb!vm::n-fixnum-tag-bits))
733
734 (deftransform sb!vm::get-lisp-obj-address ((obj) ((constant-arg character)))
735   (logior sb!vm::character-widetag
736           (ash (char-code (lvar-value obj)) sb!vm::n-widetag-bits)))