0.7.10.10:
[sbcl.git] / src / compiler / seqtran.lisp
index d2de8d2..0e50c0f 100644 (file)
                                result-type-arg-value)))))
     `(lambda (result-type-arg fun ,@seq-names)
        (truly-the ,result-type
-        ,(cond ((policy node (> speed safety))
+        ,(cond ((policy node (< safety 3))
+                ;; ANSI requires the length-related type check only
+                ;; when the SAFETY quality is 3... in other cases, we
+                ;; skip it, because it could be expensive.
                 bare)
                ((not constant-result-type-arg-p)
                 `(sequence-of-checked-length-given-type ,bare
                                                         result-type-arg))
                (t
-                (let ((result-ctype (specifier-type result-type)))
+                (let ((result-ctype (ir1-transform-specifier-type
+                                     result-type)))
                   (if (array-type-p result-ctype)
-                      (let* ((dims (array-type-dimensions result-ctype))
-                             (dim (first dims)))
-                        (if (eq dim '*)
-                            bare
-                            `(vector-of-checked-length-given-length ,bare
-                                                                    ,dim)))
+                      (let ((dims (array-type-dimensions result-ctype)))
+                        (unless (and (listp dims) (= (length dims) 1))
+                          (give-up-ir1-transform "invalid sequence type"))
+                        (let ((dim (first dims)))
+                          (if (eq dim '*)
+                              bare
+                              `(vector-of-checked-length-given-length ,bare
+                                                                      ,dim))))
+                      ;; FIXME: this is wrong, as not all subtypes of
+                      ;; VECTOR are ARRAY-TYPEs [consider, for
+                      ;; example, (OR (VECTOR T 3) (VECTOR T
+                      ;; 4))]. However, it's difficult to see what we
+                      ;; should put here... maybe we should
+                      ;; GIVE-UP-IR1-TRANSFORM if the type is a
+                      ;; subtype of VECTOR but not an ARRAY-TYPE?
                       bare))))))))
 
 ;;; Try to compile %MAP efficiently when we can determine sequence
                    (subtypep result-type-value 'vector)
                    `(coerce (apply #'%map-to-simple-vector-arity-1 fun seqs)
                             ',result-type-value))
-                  (t (give-up-ir1-transform
-                      "internal error: unexpected sequence type"))))
+                  (t (bug "impossible (?) sequence type"))))
            (t
             (let* ((seq-args (make-gensym-list (length seqs)))
                    (index-bindingoids
                      (declare (ignorable dacc))
                      ,push-dacc))))))))))
 \f
-(deftransform elt ((s i) ((simple-array * (*)) *) * :when :both)
+(deftransform elt ((s i) ((simple-array * (*)) *) *)
   '(aref s i))
 
-(deftransform elt ((s i) (list *) * :when :both)
+(deftransform elt ((s i) (list *) *)
   '(nth i s))
 
-(deftransform %setelt ((s i v) ((simple-array * (*)) * *) * :when :both)
+(deftransform %setelt ((s i v) ((simple-array * (*)) * *) *)
   '(%aset s i v))
 
 (deftransform %setelt ((s i v) (list * *))
 
 (macrolet ((def (name)
              `(deftransform ,name ((e l &key (test #'eql)) * *
-                                  :node node :when :both)
+                                  :node node)
                 (unless (constant-continuation-p l)
                   (give-up-ir1-transform))
 
                    :policy (> speed space))
   "open code"
   (let ((element-type (upgraded-element-type-specifier-or-give-up seq)))
-    `(with-array-data ((data seq)
-                      (start start)
-                      (end end))
+    (values 
+     `(with-array-data ((data seq)
+                       (start start)
+                       (end end))
        (declare (type (simple-array ,element-type 1) data))
+       (declare (type fixnum start end))
        (do ((i start (1+ i)))
           ((= i end) seq)
         (declare (type index i))
         ;; WITH-ARRAY-DATA did our range checks once and for all, so
-        ;; it'd be wasteful to check again on every AREF.
+        ;; it'd be wasteful to check again on every AREF...
         (declare (optimize (safety 0))) 
-        (setf (aref data i) item)))))
+        (setf (aref data i) item)))
+     ;; ... though we still need to check that the new element can fit
+     ;; into the vector in safe code. -- CSR, 2002-07-05
+     `((declare (type ,element-type item))))))
 \f
 ;;;; utilities
 
   ;; A form that returns the current value. This may be set with SETF to set
   ;; the current value.
   (current (error "Must specify CURRENT."))
-  ;; In a :Normal iterator, a form that tests whether there is a current value.
+  ;; In a :NORMAL iterator, a form that tests whether there is a current value.
   (done nil)
-  ;; In a :Result iterator, a form that truncates the result at the current
+  ;; In a :RESULT iterator, a form that truncates the result at the current
   ;; position and returns it.
   (result nil)
   ;; A form that returns the initial total number of values. The result is
 ;;;; calls when all arguments are vectors with the same element type,
 ;;;; rather than restricting them to STRINGs only.
 
+;;; Moved here from generic/vm-tran.lisp to satisfy clisp
+;;;
+;;; FIXME: It would be good to implement SB!XC:DEFCONSTANT, and use
+;;; use that here, so that the compiler is born knowing this value.
+;;; FIXME: Add a comment telling whether this holds for all vectors
+;;; or only for vectors based on simple arrays (non-adjustable, etc.).
+(def!constant vector-data-bit-offset
+  (* sb!vm:vector-data-offset sb!vm:n-word-bits))
+
 ;;; FIXME: Shouldn't we be testing for legality of
 ;;;   * START1, START2, END1, and END2 indices?
 ;;;   * size of copied string relative to destination string?
 ;;; %CONCATENATE (with a DEFTRANSFORM to translate constant RTYPE to
 ;;; CTYPE before calling %CONCATENATE) which is comparably efficient,
 ;;; at least once DYNAMIC-EXTENT works.
+;;;
+;;; FIXME: currently KLUDGEed because of bug 188
 (deftransform concatenate ((rtype &rest sequences)
                           (t &rest simple-string)
-                          simple-string)
+                          simple-string
+                          :policy (< safety 3))
   (collect ((lets)
            (forms)
            (all-lengths)
            (args))
     (dolist (seq sequences)
-      (declare (ignore seq))
+      (declare (ignorable seq))
       (let ((n-seq (gensym))
            (n-length (gensym)))
        (args n-seq)
        (forms `(bit-bash-copy ,n-seq ,vector-data-bit-offset
                               res start
                               ,n-length))
-       (forms `(setq start (+ start ,n-length)))))
+       (forms `(setq start (opaque-identity (+ start ,n-length))))))
     `(lambda (rtype ,@(args))
        (declare (ignore rtype))
-       (let* (,@(lets)
-             (res (make-string (truncate (the index (+ ,@(all-lengths)))
-                                         sb!vm:n-byte-bits)))
-             (start ,vector-data-bit-offset))
-        (declare (type index start ,@(all-lengths)))
-        ,@(forms)
-        res))))
+       ;; KLUDGE
+       (flet ((opaque-identity (x) x))
+        (declare (notinline opaque-identity))
+        (let* (,@(lets)
+                 (res (make-string (truncate (the index (+ ,@(all-lengths)))
+                                             sb!vm:n-byte-bits)))
+                 (start ,vector-data-bit-offset))
+          (declare (type index start ,@(all-lengths)))
+          ,@(forms)
+          res)))))
 \f
 ;;;; CONS accessor DERIVE-TYPE optimizers
 
   (check-inlineability-of-find-position-if sequence from-end)
   '(%find-position-vector-macro item sequence
                                from-end start end key test))
+
+;;; logic to unravel :TEST, :TEST-NOT, and :KEY options in FIND,
+;;; POSITION-IF, etc.
+(define-source-transform effective-find-position-test (test test-not)
+  `(cond
+    ((and ,test ,test-not)
+     (error "can't specify both :TEST and :TEST-NOT"))
+    (,test (%coerce-callable-to-fun ,test))
+    (,test-not
+     ;; (Without DYNAMIC-EXTENT, this is potentially horribly
+     ;; inefficient, but since the TEST-NOT option is deprecated
+     ;; anyway, we don't care.)
+     (complement (%coerce-callable-to-fun ,test-not)))
+    (t #'eql)))
+(define-source-transform effective-find-position-key (key)
+  `(if ,key
+       (%coerce-callable-to-fun ,key)
+       #'identity))
+
+(macrolet ((define-find-position (fun-name values-index)
+              `(define-source-transform ,fun-name (item sequence &key
+                                                   from-end (start 0) end
+                                                   key test test-not)
+                `(nth-value ,,values-index
+                  (%find-position ,item ,sequence
+                   ,from-end ,start
+                   ,end
+                   (effective-find-position-key ,key)
+                   (effective-find-position-test ,test ,test-not))))))
+  (define-find-position find 0)
+  (define-find-position position 1))
+
+(macrolet ((define-find-position-if (fun-name values-index)
+              `(define-source-transform ,fun-name (predicate sequence &key
+                                                   from-end (start 0)
+                                                   end key)
+                `(nth-value
+                  ,,values-index
+                  (%find-position-if (%coerce-callable-to-fun ,predicate)
+                   ,sequence ,from-end
+                   ,start ,end
+                   (effective-find-position-key ,key))))))
+  (define-find-position-if find-if 0)
+  (define-find-position-if position-if 1))
+
+;;; the deprecated functions FIND-IF-NOT and POSITION-IF-NOT. We
+;;; didn't bother to worry about optimizing them, except note that on
+;;; Sat, Oct 06, 2001 at 04:22:38PM +0100, Christophe Rhodes wrote on
+;;; sbcl-devel
+;;;
+;;;     My understanding is that while the :test-not argument is
+;;;     deprecated in favour of :test (complement #'foo) because of
+;;;     semantic difficulties (what happens if both :test and :test-not
+;;;     are supplied, etc) the -if-not variants, while officially
+;;;     deprecated, would be undeprecated were X3J13 actually to produce
+;;;     a revised standard, as there are perfectly legitimate idiomatic
+;;;     reasons for allowing the -if-not versions equal status,
+;;;     particularly remove-if-not (== filter).
+;;;
+;;;     This is only an informal understanding, I grant you, but
+;;;     perhaps it's worth optimizing the -if-not versions in the same
+;;;     way as the others?
+;;;
+;;; FIXME: Maybe remove uses of these deprecated functions (and
+;;; definitely of :TEST-NOT) within the implementation of SBCL.
+(macrolet ((define-find-position-if-not (fun-name values-index)
+              `(define-source-transform ,fun-name (predicate sequence &key
+                                                   from-end (start 0)
+                                                   end key)
+                `(nth-value
+                  ,,values-index
+                  (%find-position-if-not (%coerce-callable-to-fun ,predicate)
+                   ,sequence ,from-end
+                   ,start ,end
+                   (effective-find-position-key ,key))))))
+  (define-find-position-if-not find-if-not 0)
+  (define-find-position-if-not position-if-not 1))