;;; compiler-types.lisp ;;; ;;; Copyright (C) 2005-2006 Peter Graves ;;; $Id$ ;;; ;;; This program is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU General Public License ;;; as published by the Free Software Foundation; either version 2 ;;; of the License, or (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program; if not, write to the Free Software ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;;; ;;; As a special exception, the copyright holders of this library give you ;;; permission to link this library with independent modules to produce an ;;; executable, regardless of the license terms of these independent ;;; modules, and to copy and distribute the resulting executable under ;;; terms of your choice, provided that you also meet, for each linked ;;; independent module, the terms and conditions of the license of that ;;; module. An independent module is a module which is not derived from ;;; or based on this library. If you modify this library, you may extend ;;; this exception to your version of the library, but you are not ;;; obligated to do so. If you do not wish to do so, delete this ;;; exception statement from your version. ;;; Type information that matters to the compiler. (in-package #:system) (export '(+true-type+ +false-type+ integer-type-low integer-type-high integer-type-p %make-integer-type make-integer-type +fixnum-type+ +integer-type+ fixnum-type-p fixnum-constant-value integer-constant-value java-long-type-p make-compiler-type compiler-subtypep function-result-type defknown)) (defstruct constant-type value) (defconst +true-type+ (make-constant-type :value t)) (defconst +false-type+ (make-constant-type :value nil)) (defstruct (integer-type (:constructor %make-integer-type (low high))) low high) (defmethod print-object ((type integer-type) stream) (print-unreadable-object (type stream :type t :identity t) (format stream "~D ~D" (integer-type-low type) (integer-type-high type)))) (defconstant +fixnum-type+ (%make-integer-type most-negative-fixnum most-positive-fixnum)) (defconstant +integer-type+ (%make-integer-type nil nil)) (declaim (ftype (function (t) t) make-integer-type)) (defun make-integer-type (type) (if (integer-type-p type) type (cond ((eq type 'FIXNUM) +fixnum-type+) ((eq type 'INTEGER) +integer-type+) (t (setf type (normalize-type type)) (when (and (consp type) (eq (%car type) 'INTEGER)) (let ((low (second type)) (high (third type))) (if (eq low '*) (setf low nil) (when (and (consp low) (integerp (%car low))) (setf low (1+ (%car low))))) (if (eq high '*) (setf high nil) (when (and (consp high) (integerp (%car high))) (setf high (1- (%car high))))) (%make-integer-type low high))))))) (declaim (ftype (function (t) t) fixnum-type-p)) (defun fixnum-type-p (compiler-type) (and (integer-type-p compiler-type) (fixnump (integer-type-low compiler-type)) (fixnump (integer-type-high compiler-type)))) (declaim (ftype (function (t) t) fixnum-constant-value)) (defun fixnum-constant-value (compiler-type) (when (and compiler-type (integer-type-p compiler-type)) (let ((low (integer-type-low compiler-type)) high) (when (fixnump low) (setf high (integer-type-high compiler-type)) (when (and (fixnump high) (= high low)) high))))) (declaim (ftype (function (t) t) integer-constant-value)) (defun integer-constant-value (compiler-type) (when (and compiler-type (integer-type-p compiler-type)) (let ((low (integer-type-low compiler-type)) high) (when (integerp low) (setf high (integer-type-high compiler-type)) (when (and (integerp high) (= high low)) high))))) (declaim (ftype (function (t) t) java-long-type-p)) (defun java-long-type-p (compiler-type) (and (integer-type-p compiler-type) (typep (integer-type-low compiler-type) (list 'INTEGER most-negative-java-long most-positive-java-long)) (typep (integer-type-high compiler-type) (list 'INTEGER most-negative-java-long most-positive-java-long)))) (declaim (ftype (function (t t) t) make-union-type)) (defun make-union-type (type1 type2) (cond ((and (integer-type-p type1) (integer-type-p type2)) (let ((low1 (integer-type-low type1)) (low2 (integer-type-low type2)) (high1 (integer-type-high type1)) (high2 (integer-type-high type2))) (if (and low1 low2 high1 high2) (%make-integer-type (min low1 low2) (max high1 high2)) +integer-type+))) (t t))) (declaim (ftype (function (t) t) make-compiler-type)) (defun make-compiler-type (typespec) (cond ((integer-type-p typespec) typespec) ((constant-type-p typespec) typespec) ((eq typespec 'SINGLE-FLOAT) 'SINGLE-FLOAT) ((eq typespec 'DOUBLE-FLOAT) 'DOUBLE-FLOAT) ((and (consp typespec) (eq (%car typespec) 'SINGLE-FLOAT)) 'SINGLE-FLOAT) ((and (consp typespec) (eq (%car typespec) 'DOUBLE-FLOAT)) 'DOUBLE-FLOAT) (t (let ((type (normalize-type typespec))) (cond ((consp type) (let ((car (%car type))) (cond ((eq car 'INTEGER) (make-integer-type type)) ((eq car 'SINGLE-FLOAT) 'SINGLE-FLOAT) ((eq car 'DOUBLE-FLOAT) 'DOUBLE-FLOAT) ((memq car '(STRING SIMPLE-STRING LIST)) car) ((memq car '(VECTOR SIMPLE-VECTOR ARRAY SIMPLE-ARRAY)) type) ((eq car 'OR) (case (length (cdr type)) (1 (make-compiler-type (second type))) (2 (make-union-type (make-compiler-type (second type)) (make-compiler-type (third type)))) (t t))) ((subtypep type 'FIXNUM) +fixnum-type+) (t t)))) ((memq type '(BOOLEAN CHARACTER HASH-TABLE STREAM SYMBOL)) type) ((eq type 'INTEGER) (%make-integer-type nil nil)) (t t)))))) (defun integer-type-subtypep (type1 typespec) (if (eq typespec 'INTEGER) t (let ((type2 (make-integer-type typespec))) (when type2 (let ((low1 (integer-type-low type1)) (high1 (integer-type-high type1)) (low2 (integer-type-low type2)) (high2 (integer-type-high type2))) (cond ((and low1 low2 high1 high2) (and (>= low1 low2) (<= high1 high2))) ((and low1 low2 (< low1 low2)) nil) ((and high1 high2) (> high1 high2) nil) ((and (null low1) low2) nil) ((and (null high1) high2) nil) (t t))))))) (declaim (ftype (function (t t) t) compiler-subtypep)) (defun compiler-subtypep (compiler-type typespec) (cond ((eq typespec t) t) ((eq compiler-type t) nil) ((eq compiler-type typespec) t) ((eq typespec 'STRING) (eq compiler-type 'SIMPLE-STRING)) ((integer-type-p compiler-type) (integer-type-subtypep compiler-type typespec)) (t (values (subtypep compiler-type typespec))))) (declaim (type hash-table *function-result-types*)) (defvar *function-result-types* (make-hash-table :test 'equal)) (declaim (ftype (function (t) t) function-result-type)) (defun function-result-type (name) (if (symbolp name) (get name 'function-result-type) (gethash1 name *function-result-types*))) (declaim (ftype (function (t t) t) set-function-result-type)) (defun set-function-result-type (name result-type) (if (symbolp name) (setf (get name 'function-result-type) result-type) (setf (gethash name *function-result-types*) result-type))) (defun %defknown (name-or-names argument-types result-type) (let ((ftype `(function ,argument-types ,result-type)) (result-type (make-compiler-type result-type))) (cond ((or (symbolp name-or-names) (setf-function-name-p name-or-names)) (proclaim-ftype-1 ftype name-or-names) (set-function-result-type name-or-names result-type)) (t (proclaim-ftype ftype name-or-names) (dolist (name name-or-names) (set-function-result-type name result-type))))) name-or-names) (defmacro defknown (name-or-names argument-types result-type) `(eval-when (:compile-toplevel :load-toplevel :execute) (%defknown ',name-or-names ',argument-types ',result-type))) (provide '#:compiler-types)