X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Farray-tran.lisp;h=f9a4947f1d328774e06abd5d146d46d018ff154f;hb=4bc9a2b01540f3a7cbf4499b4689b292fe406139;hp=7eabbc1c93460adbdba3aa2b56a4f3e59c841e4b;hpb=7ce2c42adf3d62f03086de940adaee48e6161a40;p=sbcl.git diff --git a/src/compiler/array-tran.lisp b/src/compiler/array-tran.lisp index 7eabbc1..f9a4947 100644 --- a/src/compiler/array-tran.lisp +++ b/src/compiler/array-tran.lisp @@ -41,6 +41,12 @@ ;; 2002-08-21 *wild-type*))) +(defun extract-declared-element-type (array) + (let ((type (continuation-type array))) + (if (array-type-p type) + (array-type-element-type type) + *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 ;;; functions. @@ -58,7 +64,8 @@ array (make-array-type :complexp t :element-type *wild-type*) - (lexenv-policy (node-lexenv (continuation-dest array))))) + (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. @@ -110,11 +117,10 @@ (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)) @@ -136,14 +142,20 @@ `(,(if simple 'simple-array 'array) ,(cond ((not element-type) t) ((constant-continuation-p element-type) - (continuation-value element-type)) + (let ((ctype (careful-specifier-type + (continuation-value element-type)))) + (cond + ((or (null ctype) (unknown-type-p ctype)) '*) + (t (sb!xc:upgraded-array-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)))) + ,(cond ((constant-continuation-p dims) + (let* ((val (continuation-value dims)) + (cdims (if (listp val) val (list val)))) + (if simple + cdims + (length cdims)))) ((csubtypep (continuation-type dims) (specifier-type 'integer)) '(*)) @@ -187,13 +199,13 @@ ,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-) @@ -227,7 +239,10 @@ (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) @@ -278,37 +293,40 @@ (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) @@ -331,15 +349,36 @@ (len (if (constant-continuation-p length) (continuation-value length) '*)) - (result-type-spec `(simple-array ,eltype (,len))) (eltype-type (ir1-transform-specifier-type eltype)) + (result-type-spec + `(simple-array + ,(if (unknown-type-p eltype-type) + (give-up-ir1-transform + "ELEMENT-TYPE is an unknown type: ~S" eltype) + (sb!xc:upgraded-array-element-type eltype)) + (,len))) (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)) @@ -347,14 +386,17 @@ '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)) @@ -390,8 +432,11 @@ (rank (length dims)) (spec `(simple-array ,(cond ((null element-type) t) - ((constant-continuation-p element-type) - (continuation-value element-type)) + ((and (constant-continuation-p element-type) + (ir1-transform-specifier-type + (continuation-value element-type))) + (sb!xc:upgraded-array-element-type + (continuation-value element-type))) (t '*)) ,(make-list rank :initial-element '*)))) `(let ((header (make-array-header sb!vm:simple-array-widetag ,rank))) @@ -483,9 +528,10 @@ ;;; 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) @@ -532,14 +578,14 @@ ;;; Primitive used to verify indices into arrays. If we can tell at ;;; compile-time or we are generating unsafe code, don't bother with ;;; the VOP. -(deftransform %check-bound ((array dimension index)) - (unless (constant-continuation-p dimension) - (give-up-ir1-transform)) - (let ((dim (continuation-value dimension))) - `(the (integer 0 ,dim) index))) -(deftransform %check-bound ((array dimension index) * * - :policy (and (> speed safety) (= safety 0))) - 'index) +(deftransform %check-bound ((array dimension index) * * :node node) + (cond ((policy node (and (> speed safety) (= safety 0))) + 'index) + ((not (constant-continuation-p dimension)) + (give-up-ir1-transform)) + (t + (let ((dim (continuation-value dimension))) + `(the (integer 0 (,dim)) index))))) ;;;; WITH-ARRAY-DATA @@ -601,23 +647,27 @@ (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 @@ -657,11 +707,17 @@ `(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 @@ -785,7 +841,7 @@ (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