ecl/src/cmp/cmpprop.lsp
Marius Gerbershagen a1b1eee8b5 cmp: allow for storing type definitions in the compiler environment
Currently unused; will be used in the implementation of
cross-compilation.
2025-07-19 16:31:55 +02:00

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))