X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fsrctran.lisp;h=0661685ade6d73e5f9dea0e5002fcba67e4cf224;hb=a74b0bdb483504f6faddf8089f848f61ed94b92a;hp=487bb158052db48bc7d4faed48926bcb1764cb95;hpb=09d7974601df2aaaa820ca576026b9b4f03e6ab1;p=sbcl.git diff --git a/src/compiler/srctran.lisp b/src/compiler/srctran.lisp index 487bb15..0661685 100644 --- a/src/compiler/srctran.lisp +++ b/src/compiler/srctran.lisp @@ -258,6 +258,7 @@ ;;; Apply the function F to a bound X. If X is an open bound, then ;;; the result will be open. IF X is NIL, the result is NIL. (defun bound-func (f x) + (declare (type function f)) (and x (with-float-traps-masked (:underflow :overflow :inexact :divide-by-zero) ;; With these traps masked, we might get things like infinity @@ -688,7 +689,8 @@ ;;; result makes sense. It will if F is monotonic increasing (or ;;; non-decreasing). (defun interval-func (f x) - (declare (type interval x)) + (declare (type function f) + (type interval x)) (let ((lo (bound-func f (interval-low x))) (hi (bound-func f (interval-high x)))) (make-interval :low lo :high hi))) @@ -1072,6 +1074,7 @@ ;;; positive. If we didn't do this, we wouldn't be able to tell. (defun two-arg-derive-type (arg1 arg2 derive-fcn fcn &optional (convert-type t)) + (declare (type function derive-fcn fcn)) #!+negative-zero-is-not-zero (declare (ignore convert-type)) (flet (#!-negative-zero-is-not-zero @@ -3233,83 +3236,159 @@ nil))) (defoptimizer (coerce derive-type) ((value type)) - (let ((value-type (continuation-type value)) - (type-type (continuation-type type))) - (labels - ((good-cons-type-p (cons-type) - ;; Make sure the cons-type we're looking at is something - ;; we're prepared to handle which is basically something - ;; that array-element-type can return. - (or (and (member-type-p cons-type) - (null (rest (member-type-members cons-type))) - (null (first (member-type-members cons-type)))) - (let ((car-type (cons-type-car-type cons-type))) - (and (member-type-p car-type) - (null (rest (member-type-members car-type))) - (or (symbolp (first (member-type-members car-type))) - (numberp (first (member-type-members car-type))) - (and (listp (first (member-type-members car-type))) - (numberp (first (first (member-type-members - car-type)))))) - (good-cons-type-p (cons-type-cdr-type cons-type)))))) - (unconsify-type (good-cons-type) - ;; Convert the "printed" respresentation of a cons - ;; specifier into a type specifier. That is, the specifier - ;; (cons (eql signed-byte) (cons (eql 16) null)) is - ;; converted to (signed-byte 16). - (cond ((or (null good-cons-type) - (eq good-cons-type 'null)) - nil) - ((and (eq (first good-cons-type) 'cons) - (eq (first (second good-cons-type)) 'member)) - `(,(second (second good-cons-type)) - ,@(unconsify-type (caddr good-cons-type)))))) - (coerceable-p (c-type) - ;; Can the value be coerced to the given type? Coerce is - ;; complicated, so we don't handle every possible case - ;; here---just the most common and easiest cases: - ;; - ;; o Any real can be coerced to a float type. - ;; o Any number can be coerced to a complex single/double-float. - ;; o An integer can be coerced to an integer. - (let ((coerced-type c-type)) - (or (and (subtypep coerced-type 'float) - (csubtypep value-type (specifier-type 'real))) - (and (subtypep coerced-type - '(or (complex single-float) - (complex double-float))) - (csubtypep value-type (specifier-type 'number))) - (and (subtypep coerced-type 'integer) - (csubtypep value-type (specifier-type 'integer)))))) - (process-types (type) - ;; FIXME: - ;; This needs some work because we should be able to derive - ;; the resulting type better than just the type arg of - ;; coerce. That is, if x is (integer 10 20), the (coerce x - ;; 'double-float) should say (double-float 10d0 20d0) - ;; instead of just double-float. - (cond ((member-type-p type) - (let ((members (member-type-members type))) - (if (every #'coerceable-p members) - (specifier-type `(or ,@members)) - *universal-type*))) - ((and (cons-type-p type) - (good-cons-type-p type)) - (let ((c-type (unconsify-type (type-specifier type)))) - (if (coerceable-p c-type) - (specifier-type c-type) - *universal-type*))) - (t - *universal-type*)))) - (cond ((union-type-p type-type) - (apply #'type-union (mapcar #'process-types - (union-type-types type-type)))) - ((or (member-type-p type-type) - (cons-type-p type-type)) - (process-types type-type)) - (t - *universal-type*))))) + (cond + ((constant-continuation-p type) + ;; This branch is essentially (RESULT-TYPE-SPECIFIER-NTH-ARG 2), + ;; but dealing with the niggle that complex canonicalization gets + ;; in the way: (COERCE 1 'COMPLEX) returns 1, which is not of + ;; type COMPLEX. + (let* ((specifier (continuation-value type)) + (result-typeoid (careful-specifier-type specifier))) + (cond + ((null result-typeoid) nil) + ((csubtypep result-typeoid (specifier-type 'number)) + ;; the difficult case: we have to cope with ANSI 12.1.5.3 + ;; Rule of Canonical Representation for Complex Rationals, + ;; which is a truly nasty delivery to field. + (cond + ((csubtypep result-typeoid (specifier-type 'real)) + ;; cleverness required here: it would be nice to deduce + ;; that something of type (INTEGER 2 3) coerced to type + ;; DOUBLE-FLOAT should return (DOUBLE-FLOAT 2.0d0 3.0d0). + ;; FLOAT gets its own clause because it's implemented as + ;; a UNION-TYPE, so we don't catch it in the NUMERIC-TYPE + ;; logic below. + result-typeoid) + ((and (numeric-type-p result-typeoid) + (eq (numeric-type-complexp result-typeoid) :real)) + ;; FIXME: is this clause (a) necessary or (b) useful? + result-typeoid) + ((or (csubtypep result-typeoid + (specifier-type '(complex single-float))) + (csubtypep result-typeoid + (specifier-type '(complex double-float))) + #!+long-float + (csubtypep result-typeoid + (specifier-type '(complex long-float)))) + ;; float complex types are never canonicalized. + result-typeoid) + (t + ;; if it's not a REAL, or a COMPLEX FLOAToid, it's + ;; probably just a COMPLEX or equivalent. So, in that + ;; case, we will return a complex or an object of the + ;; provided type if it's rational: + (type-union result-typeoid + (type-intersection (continuation-type value) + (specifier-type 'rational)))))) + (t result-typeoid)))) + (t + ;; OK, the result-type argument isn't constant. However, there + ;; are common uses where we can still do better than just + ;; *UNIVERSAL-TYPE*: e.g. (COERCE X (ARRAY-ELEMENT-TYPE Y)), + ;; where Y is of a known type. See messages on cmucl-imp + ;; 2001-02-14 and sbcl-devel 2002-12-12. We only worry here + ;; about types that can be returned by (ARRAY-ELEMENT-TYPE Y), on + ;; the basis that it's unlikely that other uses are both + ;; time-critical and get to this branch of the COND (non-constant + ;; second argument to COERCE). -- CSR, 2002-12-16 + (let ((value-type (continuation-type value)) + (type-type (continuation-type type))) + (labels + ((good-cons-type-p (cons-type) + ;; Make sure the cons-type we're looking at is something + ;; we're prepared to handle which is basically something + ;; that array-element-type can return. + (or (and (member-type-p cons-type) + (null (rest (member-type-members cons-type))) + (null (first (member-type-members cons-type)))) + (let ((car-type (cons-type-car-type cons-type))) + (and (member-type-p car-type) + (null (rest (member-type-members car-type))) + (or (symbolp (first (member-type-members car-type))) + (numberp (first (member-type-members car-type))) + (and (listp (first (member-type-members + car-type))) + (numberp (first (first (member-type-members + car-type)))))) + (good-cons-type-p (cons-type-cdr-type cons-type)))))) + (unconsify-type (good-cons-type) + ;; Convert the "printed" respresentation of a cons + ;; specifier into a type specifier. That is, the + ;; specifier (CONS (EQL SIGNED-BYTE) (CONS (EQL 16) + ;; NULL)) is converted to (SIGNED-BYTE 16). + (cond ((or (null good-cons-type) + (eq good-cons-type 'null)) + nil) + ((and (eq (first good-cons-type) 'cons) + (eq (first (second good-cons-type)) 'member)) + `(,(second (second good-cons-type)) + ,@(unconsify-type (caddr good-cons-type)))))) + (coerceable-p (c-type) + ;; Can the value be coerced to the given type? Coerce is + ;; complicated, so we don't handle every possible case + ;; here---just the most common and easiest cases: + ;; + ;; * Any REAL can be coerced to a FLOAT type. + ;; * Any NUMBER can be coerced to a (COMPLEX + ;; SINGLE/DOUBLE-FLOAT). + ;; + ;; FIXME I: we should also be able to deal with characters + ;; here. + ;; + ;; FIXME II: I'm not sure that anything is necessary + ;; here, at least while COMPLEX is not a specialized + ;; array element type in the system. Reasoning: if + ;; something cannot be coerced to the requested type, an + ;; error will be raised (and so any downstream compiled + ;; code on the assumption of the returned type is + ;; unreachable). If something can, then it will be of + ;; the requested type, because (by assumption) COMPLEX + ;; (and other difficult types like (COMPLEX INTEGER) + ;; aren't specialized types. + (let ((coerced-type c-type)) + (or (and (subtypep coerced-type 'float) + (csubtypep value-type (specifier-type 'real))) + (and (subtypep coerced-type + '(or (complex single-float) + (complex double-float))) + (csubtypep value-type (specifier-type 'number)))))) + (process-types (type) + ;; FIXME: This needs some work because we should be able + ;; to derive the resulting type better than just the + ;; type arg of coerce. That is, if X is (INTEGER 10 + ;; 20), then (COERCE X 'DOUBLE-FLOAT) should say + ;; (DOUBLE-FLOAT 10d0 20d0) instead of just + ;; double-float. + (cond ((member-type-p type) + (let ((members (member-type-members type))) + (if (every #'coerceable-p members) + (specifier-type `(or ,@members)) + *universal-type*))) + ((and (cons-type-p type) + (good-cons-type-p type)) + (let ((c-type (unconsify-type (type-specifier type)))) + (if (coerceable-p c-type) + (specifier-type c-type) + *universal-type*))) + (t + *universal-type*)))) + (cond ((union-type-p type-type) + (apply #'type-union (mapcar #'process-types + (union-type-types type-type)))) + ((or (member-type-p type-type) + (cons-type-p type-type)) + (process-types type-type)) + (t + *universal-type*))))))) + +(defoptimizer (compile derive-type) ((nameoid function)) + (when (csubtypep (continuation-type nameoid) + (specifier-type 'null)) + (values-specifier-type '(values function boolean boolean)))) +;;; FIXME: Maybe also STREAM-ELEMENT-TYPE should be given some loving +;;; treatment along these lines? (See discussion in COERCE DERIVE-TYPE +;;; optimizer, above). (defoptimizer (array-element-type derive-type) ((array)) (let ((array-type (continuation-type array))) (labels ((consify (list)