0.8.0.65:
[sbcl.git] / src / compiler / array-tran.lisp
index d2eafd1..3bce548 100644 (file)
     ;; array type.
     (if (array-type-p type)
        (array-type-specialized-element-type type)
-       *universal-type*)))
+       ;; KLUDGE: there is no good answer here, but at least
+       ;; *wild-type* won't cause HAIRY-DATA-VECTOR-{REF,SET} to be
+       ;; erroneously optimized (see generic/vm-tran.lisp) -- CSR,
+       ;; 2002-08-21
+       *wild-type*)))
 
 ;;; The ``new-value'' for array setters must fit in the array, and the
 ;;; return type is going to be the same as the new-value for SETF
 (defun assert-new-value-type (new-value array)
   (let ((type (continuation-type array)))
     (when (array-type-p type)
-      (assert-continuation-type new-value
-                               (array-type-specialized-element-type type))))
+      (assert-continuation-type
+       new-value
+       (array-type-specialized-element-type type)
+       (lexenv-policy (node-lexenv (continuation-dest new-value))))))
   (continuation-type new-value))
 
+(defun assert-array-complex (array)
+  (assert-continuation-type
+   array
+   (make-array-type :complexp t
+                    :element-type *wild-type*)
+   (lexenv-policy (node-lexenv (continuation-dest array))))
+  nil)
+
 ;;; Return true if ARG is NIL, or is a constant-continuation whose
 ;;; value is NIL, false otherwise.
 (defun unsupplied-or-nil (arg)
@@ -62,7 +76,8 @@
 (defun assert-array-rank (array rank)
   (assert-continuation-type
    array
-   (specifier-type `(array * ,(make-list rank :initial-element '*)))))
+   (specifier-type `(array * ,(make-list rank :initial-element '*)))
+   (lexenv-policy (node-lexenv (continuation-dest array)))))
 
 (defoptimizer (array-in-bounds-p derive-type) ((array &rest indices))
   (assert-array-rank array (length indices))
@@ -73,7 +88,8 @@
   ;; If the node continuation has a single use then assert its type.
   (let ((cont (node-cont node)))
     (when (= (length (find-uses cont)) 1)
-      (assert-continuation-type cont (extract-upgraded-element-type array))))
+      (assert-continuation-type cont (extract-upgraded-element-type array)
+                                (lexenv-policy (node-lexenv node)))))
   (extract-upgraded-element-type array))
 
 (defoptimizer (%aset derive-type) ((array &rest stuff))
 (defoptimizer (%with-array-data derive-type) ((array start end))
   (let ((atype (continuation-type array)))
     (when (array-type-p atype)
-      (values-specifier-type
-       `(values (simple-array ,(type-specifier
-                               (array-type-specialized-element-type atype))
-                             (*))
-               index index index)))))
+      (specifier-type
+       `(simple-array ,(type-specifier
+                       (array-type-specialized-element-type atype))
+                     (*))))))
 
 (defoptimizer (array-row-major-index derive-type) ((array &rest indices))
   (assert-array-rank array (length indices))
   (let ((simple (and (unsupplied-or-nil adjustable)
                     (unsupplied-or-nil displaced-to)
                     (unsupplied-or-nil fill-pointer))))
-    (specifier-type
-     `(,(if simple 'simple-array 'array)
-       ,(cond ((not element-type) t)
-             ((constant-continuation-p element-type)
-              (continuation-value element-type))
-             (t
-              '*))
-       ,(cond ((not simple)
-              '*)
-             ((constant-continuation-p dims)
-              (let ((val (continuation-value dims)))
-                (if (listp val) val (list val))))
-             ((csubtypep (continuation-type dims)
-                         (specifier-type 'integer))
-              '(*))
-             (t
-              '*))))))
+    (or (careful-specifier-type
+         `(,(if simple 'simple-array 'array)
+            ,(cond ((not element-type) t)
+                   ((constant-continuation-p element-type)
+                    (continuation-value element-type))
+                   (t
+                    '*))
+            ,(cond ((constant-continuation-p dims)
+                    (let ((val (continuation-value dims)))
+                      (if (listp val) val (list val))))
+                   ((csubtypep (continuation-type dims)
+                               (specifier-type 'integer))
+                    '(*))
+                   (t
+                    '*))))
+        (specifier-type 'array))))
+
+;;; Complex array operations should assert that their array argument
+;;; is complex.  In SBCL, vectors with fill-pointers are complex.
+(defoptimizer (fill-pointer derive-type) ((vector))
+  (assert-array-complex vector))
+(defoptimizer (%set-fill-pointer derive-type) ((vector index))
+  (declare (ignorable index))
+  (assert-array-complex vector))
+
+(defoptimizer (vector-push derive-type) ((object vector))
+  (declare (ignorable object))
+  (assert-array-complex vector))
+(defoptimizer (vector-push-extend derive-type)
+    ((object vector &optional index))
+  (declare (ignorable object index))
+  (assert-array-complex vector))
+(defoptimizer (vector-pop derive-type) ((vector))
+  (assert-array-complex vector))
 \f
 ;;;; constructors
 
         ,n-vec))))
 
 ;;; Just convert it into a MAKE-ARRAY.
-(define-source-transform make-string (length &key
-                                            (element-type ''base-char)
-                                            (initial-element
-                                             '#.*default-init-char-form*))
-  `(make-array (the index ,length)
-              :element-type ,element-type
-              :initial-element ,initial-element))
+(deftransform make-string ((length &key
+                                  (element-type 'base-char)
+                                  (initial-element
+                                   #.*default-init-char-form*)))
+  '(make-array (the index length)
+               :element-type element-type
+               :initial-element initial-element))
 
 (defstruct (specialized-array-element-type-properties
            (:conc-name saetp-)
         (destructuring-bind (type-spec &rest rest) args
           (let ((ctype (specifier-type type-spec)))
             (apply #'!make-saetp ctype rest))))
-       `((base-char ,(code-char 0) 8 ,sb!vm:simple-string-widetag
+       `(;; Erm.  Yeah.  There aren't a lot of things that make sense
+        ;; for an initial element for (ARRAY NIL). -- CSR, 2002-03-07
+        (nil '#:mu 0 ,sb!vm:simple-array-nil-widetag)
+        (base-char ,(code-char 0) 8 ,sb!vm:simple-string-widetag
                    ;; (SIMPLE-STRINGs are stored with an extra trailing
                    ;; #\NULL for convenience in calling out to C.)
                    :n-pad-elements 1)
                         "ELEMENT-TYPE is not constant."))
                       (t
                        (continuation-value element-type))))
-        (eltype-type (specifier-type eltype))
+        (eltype-type (ir1-transform-specifier-type eltype))
         (saetp (find-if (lambda (saetp)
                           (csubtypep eltype-type (saetp-ctype saetp)))
                         *specialized-array-element-type-properties*))
-        (creation-form `(make-array dims :element-type ',eltype
-                                    ,@(when fill-pointer
-                                        '(:fill-pointer fill-pointer))
-                                    ,@(when adjustable
-                                        '(:adjustable adjustable)))))
+        (creation-form `(make-array dims
+                         :element-type ',(type-specifier (saetp-ctype saetp))
+                         ,@(when fill-pointer
+                                 '(:fill-pointer fill-pointer))
+                         ,@(when adjustable
+                                 '(:adjustable adjustable)))))
 
     (unless saetp
       (give-up-ir1-transform "ELEMENT-TYPE not found in *SAETP*: ~S" eltype))
-    
-    (cond ((or (null initial-element)
-              (and (constant-continuation-p initial-element)
-                   (eql (continuation-value initial-element)
-                        (saetp-initial-element-default saetp))))
-          (unless (csubtypep (ctype-of (saetp-initial-element-default saetp))
-                             eltype-type)
-            ;; This situation arises e.g. in (MAKE-ARRAY 4
-            ;; :ELEMENT-TYPE '(INTEGER 1 5)) ANSI's definition of
-            ;; MAKE-ARRAY says "If INITIAL-ELEMENT is not supplied,
-            ;; the consequences of later reading an uninitialized
-            ;; element of new-array are undefined," so this could be
-            ;; legal code as long as the user plans to write before
-            ;; he reads, and if he doesn't we're free to do anything
-            ;; we like. But in case the user doesn't know to write
-            ;; elements before he reads elements (or to read manuals
-            ;; before he writes code:-), we'll signal a STYLE-WARNING
-            ;; in case he didn't realize this.
-            (compiler-note "The default initial element ~S is not a ~S."
-                           (saetp-initial-element-default saetp)
-                           eltype))
+
+    (cond ((and (constant-continuation-p initial-element)
+               (eql (continuation-value initial-element)
+                    (saetp-initial-element-default saetp)))
           creation-form)
          (t
+          ;; error checking for target, disabled on the host because
+          ;; (CTYPE-OF #\Null) is not possible.
+          #-sb-xc-host
+          (when (constant-continuation-p initial-element)
+            (let ((value (continuation-value initial-element)))
+              (cond
+                ((not (ctypep value (saetp-ctype saetp)))
+                 ;; this case will cause an error at runtime, so we'd
+                 ;; better WARN about it now.
+                 (compiler-warn "~@<~S is not a ~S (which is the ~
+                                 UPGRADED-ARRAY-ELEMENT-TYPE of ~S).~@:>"
+                                value
+                                (type-specifier (saetp-ctype saetp))
+                                eltype))
+                ((not (ctypep value eltype-type))
+                 ;; this case will not cause an error at runtime, but
+                 ;; it's still worth STYLE-WARNing about.
+                 (compiler-style-warn "~S is not a ~S."
+                                      value eltype)))))
           `(let ((array ,creation-form))
             (multiple-value-bind (vector)
                 (%data-vector-and-index array 0)
               (fill vector initial-element))
             array)))))
-                        
+
 ;;; The integer type restriction on the length ensures that it will be
 ;;; a vector. The lack of :ADJUSTABLE, :FILL-POINTER, and
 ;;; :DISPLACED-TO keywords ensures that it will be simple; the lack of
                  (continuation-value length)
                  '*))
         (result-type-spec `(simple-array ,eltype (,len)))
-        (eltype-type (specifier-type eltype))
+        (eltype-type (ir1-transform-specifier-type eltype))
         (saetp (find-if (lambda (saetp)
                           (csubtypep eltype-type (saetp-ctype saetp)))
                         *specialized-array-element-type-properties*)))
     (unless saetp
       (give-up-ir1-transform
        "cannot open-code creation of ~S" result-type-spec))
-
+    #-sb-xc-host
+    (unless (csubtypep (ctype-of (saetp-initial-element-default saetp))
+                      eltype-type)
+      ;; This situation arises e.g. in (MAKE-ARRAY 4 :ELEMENT-TYPE
+      ;; '(INTEGER 1 5)) ANSI's definition of MAKE-ARRAY says "If
+      ;; INITIAL-ELEMENT is not supplied, the consequences of later
+      ;; reading an uninitialized element of new-array are undefined,"
+      ;; so this could be legal code as long as the user plans to
+      ;; write before he reads, and if he doesn't we're free to do
+      ;; anything we like. But in case the user doesn't know to write
+      ;; elements before he reads elements (or to read manuals before
+      ;; he writes code:-), we'll signal a STYLE-WARNING in case he
+      ;; didn't realize this.
+      (compiler-style-warn "The default initial element ~S is not a ~S."
+                          (saetp-initial-element-default saetp)
+                          eltype))
     (let* ((n-bits-per-element (saetp-n-bits saetp))
           (typecode (saetp-typecode saetp))
           (n-pad-elements (saetp-n-pad-elements saetp))
                                   'length
                                   `(+ length ,n-pad-elements)))
           (n-words-form
-           (if (>= n-bits-per-element sb!vm:n-word-bits)
-               `(* ,padded-length-form
-                   (the fixnum ; i.e., not RATIO
-                     ,(/ n-bits-per-element sb!vm:n-word-bits)))
-               (let ((n-elements-per-word (/ sb!vm:n-word-bits
-                                             n-bits-per-element)))
-                 (declare (type index n-elements-per-word)) ; i.e., not RATIO
-                 `(ceiling ,padded-length-form ,n-elements-per-word)))))
+           (cond
+             ((= n-bits-per-element 0) 0)
+             ((>= n-bits-per-element sb!vm:n-word-bits)
+              `(* ,padded-length-form
+                (the fixnum ; i.e., not RATIO
+                  ,(/ n-bits-per-element sb!vm:n-word-bits))))
+             (t
+              (let ((n-elements-per-word (/ sb!vm:n-word-bits
+                                            n-bits-per-element)))
+                (declare (type index n-elements-per-word)) ; i.e., not RATIO
+                `(ceiling ,padded-length-form ,n-elements-per-word))))))
       (values
        `(truly-the ,result-type-spec
         (allocate-vector ,typecode length ,n-words-form))
 
 ;;; If a simple array with known dimensions, then VECTOR-LENGTH is a
 ;;; compile-time constant.
-(deftransform vector-length ((vector) ((simple-array * (*))))
+(deftransform vector-length ((vector))
   (let ((vtype (continuation-type vector)))
-    (if (array-type-p vtype)
+    (if (and (array-type-p vtype)
+            (not (array-type-complexp vtype)))
        (let ((dim (first (array-type-dimensions vtype))))
          (when (eq dim '*) (give-up-ir1-transform))
          dim)
                  `(if (<= ,n-svalue ,n-end ,n-len)
                       ;; success
                       (values ,n-array ,n-svalue ,n-end 0)
-                      (failed-%with-array-data ,n-array ,n-svalue ,n-evalue))))
+                      (failed-%with-array-data ,n-array
+                                               ,n-svalue
+                                               ,n-evalue))))
             (,(if force-inline '%with-array-data-macro '%with-array-data)
              ,n-array ,n-svalue ,n-evalue))
        ,@forms)))
                                   (element-type '*)
                                   unsafe?
                                   fail-inline?)
-  (let ((size (gensym "SIZE-"))
-       (defaulted-end (gensym "DEFAULTED-END-"))
-       (data (gensym "DATA-"))
-       (cumulative-offset (gensym "CUMULATIVE-OFFSET-")))
+  (with-unique-names (size defaulted-end data cumulative-offset)
     `(let* ((,size (array-total-size ,array))
            (,defaulted-end
              (cond (,end
                     (unless (or ,unsafe? (<= ,end ,size))
                       ,(if fail-inline?
-                           `(error "End ~W is greater than total size ~W."
-                                   ,end ,size)
+                           `(error 'bounding-indices-bad-error
+                             :datum (cons ,start ,end)
+                             :expected-type `(cons (integer 0 ,',size)
+                                                   (integer ,',start ,',size))
+                             :object ,array)
                            `(failed-%with-array-data ,array ,start ,end)))
                     ,end)
                    (t ,size))))
        (unless (or ,unsafe? (<= ,start ,defaulted-end))
         ,(if fail-inline?
-             `(error "Start ~W is greater than end ~W." ,start ,defaulted-end)
+             `(error 'bounding-indices-bad-error
+               :datum (cons ,start ,end)
+               :expected-type `(cons (integer 0 ,',size)
+                                     (integer ,',start ,',size))
+               :object ,array)
              `(failed-%with-array-data ,array ,start ,end)))
        (do ((,data ,array (%array-data-vector ,data))
            (,cumulative-offset 0
                  `(aref (the ,',type ,a) ,@i))
                (define-source-transform ,setter (a &rest i)
                  `(%aset (the ,',type ,a) ,@i)))))
-  (define-frob svref %svset simple-vector)
-  (define-frob schar %scharset simple-string)
-  (define-frob char %charset string)
   (define-frob sbit %sbitset (simple-array bit))
   (define-frob bit %bitset (array bit)))
+(macrolet ((define-frob (reffer setter type)
+            `(progn
+               (define-source-transform ,reffer (a i)
+                 `(aref (the ,',type ,a) ,i))
+               (define-source-transform ,setter (a i v)
+                 `(%aset (the ,',type ,a) ,i ,v)))))
+  (define-frob svref %svset simple-vector)
+  (define-frob schar %scharset simple-string)
+  (define-frob char %charset string))
 
 (macrolet (;; This is a handy macro for computing the row-major index
           ;; given a set of indices. We wrap each index with a call
       (cond ((csubtypep type (specifier-type '(simple-array * (*))))
             ;; no array header
             nil)
-           ((and (listp dims) (> (length dims) 1))
+           ((and (listp dims) (/= (length dims) 1))
             ;; multi-dimensional array, will have a header
             t)
            (t