0.8.0.6:
[sbcl.git] / src / compiler / typetran.lisp
index 25e3cf9..2ec8bc6 100644 (file)
@@ -12,9 +12,6 @@
 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
 ;;;; files for more information.
 
-;;; FIXME: Many of the functions in this file could probably be
-;;; byte-compiled, since they're one-pass, cons-heavy code.
-
 (in-package "SB!C")
 \f
 ;;;; type predicate translation
           nil)
          ((csubtypep otype type)
           t)
+          ((eq type *empty-type*)
+           nil)
          (t
           (give-up-ir1-transform)))))
 
 ;;; Flush %TYPEP tests whose result is known at compile time.
 (deftransform %typep ((object type))
-  (unless (constant-continuation-p type) (give-up-ir1-transform))
+  (unless (constant-continuation-p type)
+    (give-up-ir1-transform))
   (ir1-transform-type-predicate
    object
-   (specifier-type (continuation-value type))))
+   (ir1-transform-specifier-type (continuation-value type))))
 
 ;;; This is the IR1 transform for simple type predicates. It checks
 ;;; whether the single argument is known to (not) be of the
 ;;; appropriate type, expanding to T or NIL as appropriate.
 (deftransform fold-type-predicate ((object) * * :node node :defun-only t)
-  (let ((ctype (gethash (leaf-name
+  (let ((ctype (gethash (leaf-source-name
                         (ref-leaf
                          (continuation-use
                           (basic-combination-fun node))))
 
 ;;; If FIND-CLASS is called on a constant class, locate the CLASS-CELL
 ;;; at load time.
-(deftransform find-class ((name) ((constant-argument symbol)) *
-                         :when :both)
+(deftransform find-classoid ((name) ((constant-arg symbol)) *)
   (let* ((name (continuation-value name))
-        (cell (find-class-cell name)))
-    `(or (class-cell-class ',cell)
+        (cell (find-classoid-cell name)))
+    `(or (classoid-cell-classoid ',cell)
         (error "class not yet defined: ~S" name))))
 \f
 ;;;; standard type predicates, i.e. those defined in package COMMON-LISP,
 ;;;;
 ;;;; See also VM dependent transforms.
 
-(def-source-transform atom (x)
+(define-source-transform atom (x)
   `(not (consp ,x)))
 \f
 ;;;; TYPEP source transform
 ;;; binds specified by TYPE. BASE is the name of the base type, for
 ;;; declaration. We make SAFETY locally 0 to inhibit any checking of
 ;;; this assertion.
-#!-negative-zero-is-not-zero
 (defun transform-numeric-bound-test (n-object type base)
   (declare (type numeric-type type))
   (let ((low (numeric-type-low type))
        (declare (optimize (safety 0)))
        (and ,@(when low
                (if (consp low)
-                   `((> (the ,base ,n-object) ,(car low)))
-                   `((>= (the ,base ,n-object) ,low))))
+                   `((> (truly-the ,base ,n-object) ,(car low)))
+                   `((>= (truly-the ,base ,n-object) ,low))))
            ,@(when high
                (if (consp high)
-                   `((< (the ,base ,n-object) ,(car high)))
-                   `((<= (the ,base ,n-object) ,high))))))))
-
-#!+negative-zero-is-not-zero
-(defun transform-numeric-bound-test (n-object type base)
-  (declare (type numeric-type type))
-  (let ((low (numeric-type-low type))
-       (high (numeric-type-high type))
-       (float-type-p (csubtypep type (specifier-type 'float)))
-       (x (gensym))
-       (y (gensym)))
-    `(locally
-       (declare (optimize (safety 0)))
-       (and ,@(when low
-               (if (consp low)
-                   `((let ((,x (the ,base ,n-object))
-                           (,y ,(car low)))
-                       ,(if (not float-type-p)
-                           `(> ,x ,y)
-                           `(if (and (zerop ,x) (zerop ,y))
-                                (> (float-sign ,x) (float-sign ,y))
-                                (> ,x ,y)))))
-                   `((let ((,x (the ,base ,n-object))
-                           (,y ,low))
-                       ,(if (not float-type-p)
-                           `(>= ,x ,y)
-                           `(if (and (zerop ,x) (zerop ,y))
-                                (>= (float-sign ,x) (float-sign ,y))
-                                (>= ,x ,y)))))))
-           ,@(when high
-               (if (consp high)
-                   `((let ((,x (the ,base ,n-object))
-                           (,y ,(car high)))
-                       ,(if (not float-type-p)
-                            `(< ,x ,y)
-                            `(if (and (zerop ,x) (zerop ,y))
-                                 (< (float-sign ,x) (float-sign ,y))
-                                 (< ,x ,y)))))
-                   `((let ((,x (the ,base ,n-object))
-                           (,y ,high))
-                       ,(if (not float-type-p)
-                            `(<= ,x ,y)
-                            `(if (and (zerop ,x) (zerop ,y))
-                                 (<= (float-sign ,x) (float-sign ,y))
-                                 (<= ,x ,y)))))))))))
+                   `((< (truly-the ,base ,n-object) ,(car high)))
+                   `((<= (truly-the ,base ,n-object) ,high))))))))
 
 ;;; Do source transformation of a test of a known numeric type. We can
 ;;; assume that the type doesn't have a corresponding predicate, since
               ,(transform-numeric-bound-test n-object type base)))
        (:complex
         `(and (complexp ,n-object)
-              ,(once-only ((n-real `(realpart (the complex ,n-object)))
-                           (n-imag `(imagpart (the complex ,n-object))))
+              ,(once-only ((n-real `(realpart (truly-the complex ,n-object)))
+                           (n-imag `(imagpart (truly-the complex ,n-object))))
                  `(progn
                     ,n-imag ; ignorable
                     (and (typep ,n-real ',base)
             (satisfies `(if (funcall #',(second spec) ,object) t nil))
             ((not and)
              (once-only ((n-obj object))
-               `(,(first spec) ,@(mapcar #'(lambda (x)
-                                             `(typep ,n-obj ',x))
+               `(,(first spec) ,@(mapcar (lambda (x)
+                                           `(typep ,n-obj ',x))
                                          (rest spec))))))))))
 
+(defun source-transform-negation-typep (object type)
+  (declare (type negation-type type))
+  (let ((spec (type-specifier (negation-type-type type))))
+    `(not (typep ,object ',spec))))
+
 ;;; Do source transformation for TYPEP of a known union type. If a
 ;;; union type contains LIST, then we pull that out and make it into a
 ;;; single LISTP call. Note that if SYMBOL is in the union, then LIST
 (defun source-transform-cons-typep (object type)
   (let* ((car-type (cons-type-car-type type))
         (cdr-type (cons-type-cdr-type type)))
-    (let ((car-test-p (not (or (type= car-type *wild-type*)
-                              (type= car-type (specifier-type t)))))
-         (cdr-test-p (not (or (type= cdr-type *wild-type*)
-                              (type= cdr-type (specifier-type t))))))
+    (let ((car-test-p (not (type= car-type *universal-type*)))
+         (cdr-test-p (not (type= cdr-type *universal-type*))))
       (if (and (not car-test-p) (not cdr-test-p))
          `(consp ,object)
          (once-only ((n-obj object))
 ;;; then we also check whether the layout for the object is invalid
 ;;; and signal an error if so. Otherwise, look up the indirect
 ;;; class-cell and call CLASS-CELL-TYPEP at runtime.
-;;;
-;;; KLUDGE: The :WHEN :BOTH option here is probably a suboptimal
-;;; solution to the problem of %INSTANCE-TYPEP forms in byte compiled
-;;; code; it'd probably be better just to have %INSTANCE-TYPEP forms
-;;; never be generated in byte compiled code, or maybe to have a DEFUN
-;;; %INSTANCE-TYPEP somewhere to handle them if they are. But it's not
-;;; terribly important because mostly, %INSTANCE-TYPEP forms *aren't*
-;;; generated in byte compiled code. (As of sbcl-0.6.5, they could
-;;; sometimes be generated when byte compiling inline functions, but
-;;; it's quite uncommon.) -- WHN 20000523
-(deftransform %instance-typep ((object spec) (* *) * :node node :when :both)
+(deftransform %instance-typep ((object spec) (* *) * :node node)
   (aver (constant-continuation-p spec))
   (let* ((spec (continuation-value spec))
         (class (specifier-type spec))
-        (name (sb!xc:class-name class))
+        (name (classoid-name class))
         (otype (continuation-type object))
         (layout (let ((res (info :type :compiler-layout name)))
                   (if (and res (not (layout-invalid res)))
       ((csubtypep otype class)
        t)
       ;; If not properly named, error.
-      ((not (and name (eq (sb!xc:find-class name) class)))
+      ((not (and name (eq (find-classoid name) class)))
        (compiler-error "can't compile TYPEP of anonymous or undefined ~
                        class:~%  ~S"
                       class))
             (t
              (values '(lambda (x) (declare (ignore x)) t) 'layout-of)))
         (cond
-          ((and (eq (class-state class) :sealed) layout
-                (not (class-subclasses class)))
+          ((and (eq (classoid-state class) :sealed) layout
+                (not (classoid-subclasses class)))
            ;; Sealed and has no subclasses.
            (let ((n-layout (gensym)))
              `(and (,pred object)
                              `((when (layout-invalid ,n-layout)
                                  (%layout-invalid-error object ',layout))))
                      (eq ,n-layout ',layout)))))
-          ((and (typep class 'basic-structure-class) layout)
+          ((and (typep class 'basic-structure-classoid) layout)
            ;; structure type tests; hierarchical layout depths
            (let ((depthoid (layout-depthoid layout))
                  (n-layout (gensym)))
           (t
            (/noshow "default case -- ,PRED and CLASS-CELL-TYPEP")
            `(and (,pred object)
-                 (class-cell-typep (,get-layout object)
-                                   ',(find-class-cell name)
-                                   object)))))))))
+                 (classoid-cell-typep (,get-layout object)
+                                      ',(find-classoid-cell name)
+                                      object)))))))))
 
 ;;; If the specifier argument is a quoted constant, then we consider
 ;;; converting into a simple predicate or other stuff. If the type is
 ;;; If the type is TYPE= to a type that has a predicate, then expand
 ;;; to that predicate. Otherwise, we dispatch off of the type's type.
 ;;; These transformations can increase space, but it is hard to tell
-;;; when, so we ignore policy and always do them. When byte-compiling,
-;;; we only do transforms that have potential for control
-;;; simplification. Instance type tests are converted to
-;;; %INSTANCE-TYPEP to allow type propagation.
-(def-source-transform typep (object spec)
+;;; when, so we ignore policy and always do them. 
+(define-source-transform typep (object spec)
   ;; KLUDGE: It looks bad to only do this on explicitly quoted forms,
   ;; since that would overlook other kinds of constants. But it turns
   ;; out that the DEFTRANSFORM for TYPEP detects any constant
   ;; source transform another chance, so it all works out OK, in a
   ;; weird roundabout way. -- WHN 2001-03-18
   (if (and (consp spec) (eq (car spec) 'quote))
-      (let ((type (specifier-type (cadr spec))))
-       (or (let ((pred (cdr (assoc type *backend-type-predicates*
+      (let ((type (careful-specifier-type (cadr spec))))
+       (or (when (not type)
+              (compiler-warn "illegal type specifier for TYPEP: ~S"
+                             (cadr spec))
+              `(%typep ,object ,spec))
+            (let ((pred (cdr (assoc type *backend-type-predicates*
                                    :test #'type=))))
              (when pred `(,pred ,object)))
            (typecase type
              (hairy-type
               (source-transform-hairy-typep object type))
+             (negation-type
+              (source-transform-negation-typep object type))
              (union-type
               (source-transform-union-typep object type))
              (intersection-type
              (member-type
               `(member ,object ',(member-type-members type)))
              (args-type
-              (compiler-warning "illegal type specifier for TYPEP: ~S"
-                                (cadr spec))
+              (compiler-warn "illegal type specifier for TYPEP: ~S"
+                             (cadr spec))
               `(%typep ,object ,spec))
              (t nil))
-           (and (not (byte-compiling))
-                (typecase type
-                  (numeric-type
-                   (source-transform-numeric-typep object type))
-                  (sb!xc:class
-                   `(%instance-typep ,object ,spec))
-                  (array-type
-                   (source-transform-array-typep object type))
-                  (cons-type
-                   (source-transform-cons-typep object type))
-                  (t nil)))
+           (typecase type
+             (numeric-type
+              (source-transform-numeric-typep object type))
+             (classoid
+              `(%instance-typep ,object ,spec))
+             (array-type
+              (source-transform-array-typep object type))
+             (cons-type
+              (source-transform-cons-typep object type))
+             (t nil))
            `(%typep ,object ,spec)))
       (values nil t)))
 \f
 ;;;; coercion
 
-;;; old working version
-(deftransform coerce ((x type) (* *) * :when :both)
+(deftransform coerce ((x type) (* *) * :node node)
   (unless (constant-continuation-p type)
     (give-up-ir1-transform))
-  (let ((tspec (specifier-type (continuation-value type))))
+  (let ((tspec (ir1-transform-specifier-type (continuation-value type))))
     (if (csubtypep (continuation-type x) tspec)
        'x
+       ;; Note: The THE here makes sure that specifiers like
+       ;; (SINGLE-FLOAT 0.0 1.0) can raise a TYPE-ERROR.
        `(the ,(continuation-value type)
-             ,(cond ((csubtypep tspec (specifier-type 'double-float))
-                     '(%double-float x))       
-                    ;; FIXME: If LONG-FLOAT is to be supported, we
-                    ;; need to pick it off here before falling through
-                    ;; to %SINGLE-FLOAT.
-                    ((csubtypep tspec (specifier-type 'float))
-                     '(%single-float x))
-                    (t
-                     (give-up-ir1-transform)))))))
+          ,(cond
+            ((csubtypep tspec (specifier-type 'double-float))
+             '(%double-float x))
+            ;; FIXME: #!+long-float (t ,(error "LONG-FLOAT case needed"))
+            ((csubtypep tspec (specifier-type 'float))
+             '(%single-float x))
+            ((and (csubtypep tspec (specifier-type 'simple-vector))
+                  ;; Can we avoid checking for dimension issues like
+                  ;; (COERCE FOO '(SIMPLE-VECTOR 5)) returning a
+                  ;; vector of length 6?
+                  (or (policy node (< safety 3)) ; no need in unsafe code
+                      (and (array-type-p tspec) ; no need when no dimensions
+                           (equal (array-type-dimensions tspec) '(*)))))
+             `(if (simple-vector-p x)
+                  x
+                  (replace (make-array (length x)) x)))
+            ;; FIXME: other VECTOR types?
+            (t
+             (give-up-ir1-transform)))))))
+
 
-;;; KLUDGE: new broken version -- 20000504
-;;; FIXME: should be fixed or deleted
-#+nil
-(deftransform coerce ((x type) (* *) * :when :both)
-  (unless (constant-continuation-p type)
-    (give-up-ir1-transform))
-  (let ((tspec (specifier-type (continuation-value type))))
-    (if (csubtypep (continuation-type x) tspec)
-       'x
-       `(if #+nil (typep x type) #-nil nil
-            x
-            (the ,(continuation-value type)
-                 ,(cond ((csubtypep tspec (specifier-type 'double-float))
-                         '(%double-float x))   
-                        ;; FIXME: If LONG-FLOAT is to be supported,
-                        ;; we need to pick it off here before falling
-                        ;; through to %SINGLE-FLOAT.
-                        ((csubtypep tspec (specifier-type 'float))
-                         '(%single-float x))
-                        #+nil
-                        ((csubtypep tspec (specifier-type 'list))
-                         '(coerce-to-list x))
-                        #+nil
-                        ((csubtypep tspec (specifier-type 'string))
-                         '(coerce-to-simple-string x))
-                        #+nil
-                        ((csubtypep tspec (specifier-type 'bit-vector))
-                         '(coerce-to-bit-vector x))
-                        #+nil
-                        ((csubtypep tspec (specifier-type 'vector))
-                         '(coerce-to-vector x type))
-                        (t
-                         (give-up-ir1-transform))))))))