(if (template-p (basic-combination-info node))
(ir2-convert-template node block)
(ir2-convert-full-call node block))))
+
+;; just a fancy identity
+(defoptimizer (%typep-wrapper ir2-convert) ((value variable type) node block)
+ (let* ((lvar (node-lvar node))
+ (results (lvar-result-tns lvar (list (primitive-type-or-lose t)))))
+ (emit-move node block (lvar-tn node block value) (first results))
+ (move-lvar-result node block results lvar)))
\f
;;; Convert the code in a component into VOPs.
(defun ir2-convert (component)
`(or (classoid-cell-classoid ',cell)
(error "class not yet defined: ~S" name))))
\f
+(defoptimizer (%typep-wrapper constraint-propagate-if)
+ ((test-value variable type) node gen)
+ (aver (constant-lvar-p type))
+ (let ((type (lvar-value type)))
+ (values variable (if (ctype-p type)
+ type
+ (handler-case (careful-specifier-type type)
+ (t () nil))))))
+
+(deftransform %typep-wrapper ((test-value variable type) * * :node node)
+ (aver (constant-lvar-p type))
+ (if (constant-lvar-p test-value)
+ `',(lvar-value test-value)
+ (let* ((type (lvar-value type))
+ (type (if (ctype-p type)
+ type
+ (handler-case (careful-specifier-type type)
+ (t () nil))))
+ (value-type (lvar-type variable)))
+ (cond ((not type)
+ 'test-value)
+ ((csubtypep value-type type)
+ t)
+ ((not (types-equal-or-intersect value-type type))
+ nil)
+ (t
+ (delay-ir1-transform node :constraint)
+ 'test-value)))))
+\f
;;;; standard type predicates, i.e. those defined in package COMMON-LISP,
;;;; plus at least one oddball (%INSTANCEP)
;;;;
;;; 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.
-(defun source-transform-typep (object type)
+(defun %source-transform-typep (object type)
(let ((ctype (careful-specifier-type type)))
(or (when (not ctype)
(compiler-warn "illegal type specifier for TYPEP: ~S" type)
- (return-from source-transform-typep (values nil t)))
+ (return-from %source-transform-typep (values nil t)))
(multiple-value-bind (constantp value) (type-singleton-p ctype)
(and constantp
`(eql ,object ',value)))
`(if (member ,object ',(member-type-members ctype)) t))
(args-type
(compiler-warn "illegal type specifier for TYPEP: ~S" type)
- (return-from source-transform-typep (values nil t)))
+ (return-from %source-transform-typep (values nil t)))
(t nil))
(typecase ctype
(numeric-type
(t nil))
`(%typep ,object ',type))))
+(defun source-transform-typep (object type)
+ (let ((name (gensym "OBJECT")))
+ (multiple-value-bind (transform error)
+ (%source-transform-typep name type)
+ (if error
+ (values nil t)
+ (values `(let ((,name ,object))
+ (%typep-wrapper ,transform ,name ',type)))))))
+
(define-source-transform typep (object spec &optional env)
;; KLUDGE: It looks bad to only do this on explicitly quoted forms,
;; since that would overlook other kinds of constants. But it turns
+
;;;; various compiler tests without side effects
;;;; This software is part of the SBCL system. See the README file for
(test every)
(test notany)
(test notevery))))
+
+(with-test (:name :propagate-complex-type-tests)
+ (flet ((test (type value)
+ (let ((ftype (sb-kernel:%simple-fun-type
+ (compile nil `(lambda (x)
+ (if (typep x ',type)
+ x
+ ',value))))))
+ (assert (typep ftype `(cons (eql function))))
+ (assert (= 3 (length ftype)))
+ (let* ((return (third ftype))
+ (rtype (second return)))
+ (assert (typep return `(cons (eql values)
+ (cons t
+ (cons (eql &optional)
+ null)))))
+ (assert (and (subtypep rtype type)
+ (subtypep type rtype)))))))
+ (mapc (lambda (params)
+ (apply #'test params))
+ `(((unsigned-byte 17) 0)
+ ((member 1 3 5 7) 5)
+ ((or symbol (eql 42)) t)))))
+
+(with-test (:name :constant-fold-complex-type-tests)
+ (assert (equal (sb-kernel:%simple-fun-type
+ (compile nil `(lambda (x)
+ (if (typep x '(member 1 3))
+ (typep x '(member 1 3 15))
+ t))))
+ `(function (t) (values (member t) &optional))))
+ (assert (equal (sb-kernel:%simple-fun-type
+ (compile nil `(lambda (x)
+ (declare (type (member 1 3) x))
+ (typep x '(member 1 3 15)))))
+ `(function ((or (integer 1 1) (integer 3 3)))
+ (values (member t) &optional)))))