mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-03-11 07:20:29 -07:00
305 lines
10 KiB
Common Lisp
305 lines
10 KiB
Common Lisp
;;;; -*- Mode: Lisp; Syntax: Common-Lisp; indent-tabs-mode: nil; Package: C -*-
|
|
;;;; vim: set filetype=lisp tabstop=8 shiftwidth=2 expandtab:
|
|
|
|
;;;;
|
|
;;;; Copyright (c) 2010, Juan Jose Garcia-Ripoll
|
|
;;;;
|
|
;;;;
|
|
;;;; See the file 'LICENSE' for the copyright details.
|
|
;;;;
|
|
|
|
;;;; CMPPROP Type propagation.
|
|
|
|
(in-package "COMPILER")
|
|
|
|
(eval-when (:execute :load-toplevel :compile-toplevel)
|
|
(defparameter *type-propagation-messages* nil)
|
|
(defmacro prop-message (string &rest args)
|
|
(when *type-propagation-messages*
|
|
`(format *standard-output* ,string ,@args))))
|
|
|
|
(defun p1ordinary (c1form form)
|
|
(declare (ignore c1form))
|
|
(p1propagate form))
|
|
|
|
(defun p1fset (c1form fun fname macro pprint c1forms)
|
|
(declare (ignore c1form fname macro pprint c1forms))
|
|
(p1propagate-function fun)
|
|
'function)
|
|
|
|
(defun p1propagate (form)
|
|
(unless form
|
|
(return-from p1propagate 'null))
|
|
(when (c1form-p form)
|
|
(let ((*cmp-env* (c1form-env form))
|
|
(*compile-file-pathname* (c1form-file form))
|
|
(*compile-file-position* (c1form-file-position form))
|
|
(*current-form* (c1form-form form))
|
|
(*current-toplevel-form* (c1form-toplevel-form form))
|
|
(name (c1form-name form)))
|
|
(ext:when-let ((propagator (gethash name *p1-dispatch-table*)))
|
|
(prop-message "~&;;; Entering type propagation for ~A" name)
|
|
(let ((new-type (apply propagator form (c1form-args form))))
|
|
(prop-message "~&;;; Propagating ~A gives type ~A" name new-type)
|
|
(return-from p1propagate
|
|
(setf (c1form-type form)
|
|
(values-type-and (c1form-type form) new-type)))))))
|
|
(cmpnote "Refusing to propagate ~A" form)
|
|
(c1form-type form))
|
|
|
|
(defun p1trivial (form &rest rest)
|
|
(declare (ignore rest))
|
|
(c1form-type form))
|
|
|
|
(defun p1var (form var loc)
|
|
;; Use the type of C1FORM because it might have been coerced by a THE form.
|
|
(let* ((loc-type (if loc (loc-lisp-type loc) t))
|
|
(var-type (loc-lisp-type var))
|
|
(type (type-and (type-and loc-type var-type)
|
|
(c1form-primary-type form))))
|
|
(prop-message "~&;;; Querying variable ~A gives ~A" (var-name var) type)
|
|
type))
|
|
|
|
(defun p1values (form values)
|
|
(declare (ignore form))
|
|
(loop for v in values
|
|
collect (values-type-primary-type (p1propagate v))
|
|
into all-values
|
|
finally (return `(values ,@all-values))))
|
|
|
|
(defun p1propagate-list (list)
|
|
(loop with final-type = t
|
|
for f in list
|
|
do (setf final-type (p1propagate f))
|
|
finally (return final-type)))
|
|
|
|
(defun p1block (c1form blk body)
|
|
(declare (ignore c1form))
|
|
(setf (blk-type blk) nil)
|
|
(let ((normal-type (p1propagate body))
|
|
(blk-type (blk-type blk)))
|
|
(if blk-type
|
|
(values-type-or blk-type normal-type)
|
|
normal-type)))
|
|
|
|
(defun p1return-from (c1form blk return-type value)
|
|
(declare (ignore c1form return-type))
|
|
(let* ((values-type (p1propagate value))
|
|
(blk-type (blk-type blk)))
|
|
(setf (blk-type blk) (if blk-type
|
|
(values-type-or blk-type values-type)
|
|
values-type))
|
|
values-type))
|
|
|
|
(defun p1fcall (c1form fun args fun-val call-type)
|
|
(p1propagate fun)
|
|
(p1propagate-list args)
|
|
(ecase call-type
|
|
(:global
|
|
(propagate-types fun-val args))
|
|
(:local
|
|
(flet ((and-form-type (type form)
|
|
(and-form-type type form (c1form-form form)
|
|
:safe "In a call to ~a" (fun-name fun-val))))
|
|
(loop with local-arg-types = (get-local-arg-types fun-val)
|
|
for arg-form in args
|
|
for arg-type = (pop local-arg-types)
|
|
when arg-type
|
|
do (and-form-type arg-type arg-form)
|
|
do (p1propagate arg-form))
|
|
(let ((dcl-return (or (get-local-return-type fun-val) '(VALUES &REST T)))
|
|
(fun-return (fun-return-type fun-val)))
|
|
(and-call-type dcl-return c1form)
|
|
(and-call-type fun-return c1form)
|
|
(p1trivial c1form))))
|
|
(:unknown
|
|
(p1trivial c1form))))
|
|
|
|
(defun p1mcall (c1form fun args fun-val call-type)
|
|
(p1propagate fun)
|
|
(p1propagate-list args)
|
|
(ecase call-type
|
|
(:global (or (get-return-type fun-val) '(VALUES &REST T)))
|
|
(:local (or (get-local-return-type fun-val) '(VALUES &REST T)))
|
|
(:unknown (p1trivial c1form))))
|
|
|
|
(defun p1catch (c1form tag body)
|
|
(declare (ignore c1form))
|
|
(p1propagate tag)
|
|
(p1propagate body)
|
|
t)
|
|
|
|
(defun p1throw (c1form catch-value output-value)
|
|
(declare (ignore c1form))
|
|
(p1propagate catch-value)
|
|
(p1propagate output-value)
|
|
t)
|
|
|
|
(defun p1if (c1form fmla true-branch false-branch)
|
|
(declare (ignore c1form))
|
|
(let ((t0 (values-type-primary-type (p1propagate fmla))))
|
|
(cond ((type-true-p t0 *cmp-env*)
|
|
(p1propagate true-branch))
|
|
((type-false-p t0 *cmp-env*)
|
|
(p1propagate false-branch))
|
|
(t (let ((t1 (p1propagate true-branch))
|
|
(t2 (p1propagate false-branch)))
|
|
(values-type-or t1 t2))))))
|
|
|
|
(defun p1fmla-not (c1form form)
|
|
(declare (ignore c1form))
|
|
(let ((t0 (values-type-primary-type (p1propagate form))))
|
|
(cond ((type-true-p t0 *cmp-env*)
|
|
'(eql nil))
|
|
((type-false-p t0 *cmp-env*)
|
|
'(eql t))
|
|
(t
|
|
'(member t nil)))))
|
|
|
|
(defun p1fmla-and (c1form butlast last)
|
|
(declare (ignore c1form))
|
|
(loop with all-true = t
|
|
for form in butlast
|
|
for type = (p1propagate form)
|
|
for primary-type = (values-type-primary-type type)
|
|
do (when (type-false-p primary-type *cmp-env*)
|
|
(return-from p1fmla-and primary-type))
|
|
(unless (type-true-p primary-type *cmp-env*)
|
|
(setf all-true nil))
|
|
finally
|
|
(setf type (p1propagate last)
|
|
primary-type (values-type-primary-type type))
|
|
(return (if (or (type-false-p primary-type *cmp-env*)
|
|
(and (type-true-p primary-type *cmp-env*) all-true))
|
|
type
|
|
(values-type-or 'null type)))))
|
|
|
|
(defun p1fmla-or (c1form butlast last)
|
|
(declare (ignore c1form))
|
|
(loop for form in butlast
|
|
for type = (p1propagate form)
|
|
for primary-type = (values-type-primary-type type)
|
|
for output-type = primary-type then (type-or primary-type output-type)
|
|
do (when (type-true-p primary-type *cmp-env*)
|
|
(return-from p1fmla-or (type-and output-type '(not null))))
|
|
finally
|
|
(setf type (p1propagate last)
|
|
primary-type (values-type-primary-type type)
|
|
output-type (values-type-or type output-type))
|
|
(return (if (type-true-p primary-type *cmp-env*)
|
|
(values-type-and output-type '(not null))
|
|
output-type))))
|
|
|
|
(defun p1lambda (c1form lambda-list doc body &rest not-used)
|
|
(declare (ignore c1form lambda-list doc not-used))
|
|
(prop-message "~&;;;~&;;; Propagating function~&;;;")
|
|
(p1propagate body))
|
|
|
|
(defun p1propagate-function (fun)
|
|
(setf (fun-return-type fun) (p1propagate (fun-lambda fun))))
|
|
|
|
(defun p1let* (c1form vars forms body)
|
|
(declare (ignore c1form))
|
|
(loop with type
|
|
for v in vars
|
|
for f in forms
|
|
unless (or (global-var-p v) (var-set-nodes v))
|
|
do (progn
|
|
(setf type (p1propagate f))
|
|
(setf (var-type v)
|
|
(type-and (values-type-primary-type type) (var-type v)))
|
|
(prop-message "~&;;; Variable ~A assigned type ~A"
|
|
(var-name v) (var-type v))))
|
|
(p1propagate body))
|
|
|
|
(defun p1locals (c1form funs body labels)
|
|
(declare (ignore c1form labels))
|
|
(loop for f in funs
|
|
do (p1propagate-function f))
|
|
(p1propagate body))
|
|
|
|
(defun p1multiple-value-bind (c1form vars-list init-c1form body)
|
|
(declare (ignore c1form))
|
|
(let ((init-form-type (p1propagate init-c1form)))
|
|
(loop for v in vars-list
|
|
for type in (values-type-to-n-types init-form-type (length vars-list))
|
|
unless (or (global-var-p v)
|
|
(var-set-nodes v))
|
|
do (setf (var-type v) (type-and (var-type v) type)) and
|
|
do (prop-message "~&;;; Variable ~A assigned type ~A"
|
|
(var-name v) (var-type v)))
|
|
(p1propagate body)))
|
|
|
|
(defun p1multiple-value-setq (c1form vars-list value-c1form)
|
|
(declare (ignore c1form vars-list))
|
|
(p1propagate value-c1form))
|
|
|
|
(defun p1progn (c1form forms)
|
|
(declare (ignore c1form))
|
|
(p1propagate-list forms))
|
|
|
|
(defun p1compiler-typecase (c1form variable expressions)
|
|
(declare (ignore c1form))
|
|
(let ((var-type (var-type variable)))
|
|
(loop with output-type = t
|
|
for (a-type c1form) in expressions
|
|
for c1form-type = (p1propagate c1form)
|
|
when (or (member a-type '(t otherwise))
|
|
(subtypep var-type a-type *cmp-env*))
|
|
do (setf output-type c1form-type)
|
|
finally (return output-type))))
|
|
|
|
(defun p1checked-value (c1form type value let-form)
|
|
(declare (ignore c1form let-form))
|
|
(let ((value-type (p1propagate value))
|
|
;;(alt-type (p1propagate let-form))
|
|
)
|
|
(if (subtypep value-type type *cmp-env*)
|
|
value-type
|
|
type)))
|
|
|
|
(defun p1progv (c1form variables values body)
|
|
(declare (ignore c1form))
|
|
(p1propagate variables)
|
|
(p1propagate values)
|
|
(p1propagate body))
|
|
|
|
(defun p1setq (c1form var value-c1form)
|
|
(declare (ignore c1form))
|
|
(let ((value-type (p1propagate value-c1form)))
|
|
(type-and (var-type var) (values-type-primary-type value-type))))
|
|
|
|
(defun p1psetq (c1form vars c1forms)
|
|
(declare (ignore c1form vars))
|
|
(loop for form in c1forms
|
|
do (p1propagate form))
|
|
'null)
|
|
|
|
(defun p1mv-prog1 (c1form form body)
|
|
(declare (ignore c1form))
|
|
(prog1 (p1propagate form)
|
|
(p1propagate-list body)))
|
|
|
|
(defvar *tagbody-depth* -1
|
|
"If n > 0, limit the number of passes to converge tagbody forms. If
|
|
-1, let the compiler do as many passes as it wishes. Complexity grows
|
|
as 2^*tagbody-limit* in the worst cases.")
|
|
|
|
(defun p1go (c1form tag-var return-type)
|
|
(declare (ignore c1form tag-var return-type))
|
|
t)
|
|
|
|
(defun p1tagbody (c1form tag-loc body)
|
|
(declare (ignore c1form tag-loc))
|
|
(prop-message "~&;;; P1TAGBODY-SIMPLE pass")
|
|
(loop for f in body do
|
|
(if (tag-p f)
|
|
(prop-message "~&;;; Label ~A found" (tag-name f))
|
|
(p1propagate f)))
|
|
'null)
|
|
|
|
(defun p1unwind-protect (c1form form body)
|
|
(declare (ignore c1form))
|
|
(let ((output-type (p1propagate form)))
|
|
(p1propagate body)
|
|
output-type))
|