;;;-*- Mode: Lisp; Package: CCL -*- ;;; ;;; Copyright (C) 2007-2010 Clozure Associates ;;; This file is part of Clozure CL. ;;; ;;; Clozure CL is licensed under the terms of the Lisp Lesser GNU Public ;;; License , known as the LLGPL and distributed with Clozure CL as the ;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL, ;;; which is distributed with Clozure CL as the file "LGPL". Where these ;;; conflict, the preamble takes precedence. ;;; ;;; Clozure CL is referenced in the preamble as the "LIBRARY." ;;; ;;; The LLGPL is also available online at ;;; http://opensource.franz.com/preamble.html (in-package "CCL") (defvar *acode-rewrite-tail-allow* nil) (defvar *acode-rewrite-reckless* nil) (defvar *acode-rewrite-open-code-inline* nil) (defvar *acode-rewrite-trust-declarations* nil) (defvar *acode-rewrite-full-safety* nil) ;;; Rewrite acode trees. (defvar *acode-rewrite-functions* nil) (let* ((newsize (%i+ (next-nx-num-ops) 10)) (old *acode-rewrite-functions*) (oldsize (length old))) (declare (fixnum newsize oldsize)) (unless (>= oldsize newsize) (let* ((v (make-array newsize :initial-element nil))) (dotimes (i oldsize (setq *acode-rewrite-functions* v)) (setf (svref v i) (svref old i)))))) (eval-when (:compile-toplevel :load-toplevel :execute) (defmacro def-acode-rewrite (name operator-list typecons arglist &body body) (if (atom operator-list) (setq operator-list (list operator-list))) (multiple-value-bind (lambda-list whole) (normalize-lambda-list arglist t) (multiple-value-bind (body decls) (parse-body body nil t) (collect ((let-body)) (dolist (operator operator-list) (let-body `(setf (svref *acode-rewrite-functions* (logand operator-id-mask (%nx1-operator ,operator))) fun))) (let* ((whole-var (gensym "WHOLE"))) (multiple-value-bind (bindings binding-decls) (%destructure-lambda-list lambda-list whole-var nil nil :cdr-p t :whole-p nil :use-whole-var t :default-initial-value nil) (when whole (setq bindings (nconc bindings (list `(,whole ,whole-var))))) `(let* ((fun (nfunction ,name (lambda (,typecons ,whole-var) (declare (ignorable ,typecons)) (block ,name (let* ,(nreverse bindings) ,@(when binding-decls `((declare ,@binding-decls))) ,@decls ,@body)))))) ,@(let-body))))))))) ;;; Don't walk the form (that's already happened.) (defun acode-post-form-type (form) (when (acode-p form) (let* ((op (acode-operator form)) (operands (cdr form))) (cond ((and *acode-rewrite-trust-declarations* (eq op (%nx1-operator typed-form))) (acode-operand 0 operands)) ((eq op (%nx1-operator fixnum)) 'fixnum) ((eq op (%nx1-operator immediate)) (type-of (acode-operand 0 operands))) (t t))))) (defun acode-post-form-typep (form type) (let* ((ctype (specifier-type type)) (form (acode-unwrapped-form-value form))) (cond ((nx-null form) (ctypep nil ctype)) ((nx-t form) (ctypep t ctype)) ((not (acode-p form)) (values nil nil)) (t (let* ((op (acode-operator form)) (operands (cdr form))) (cond ((and *acode-rewrite-trust-declarations* (eq op (%nx1-operator typed-form))) (subtypep (acode-operand 0 operands) type)) ((or (eq op (%nx1-operator fixnum)) (eq op (%nx1-operator immediate))) (ctypep (acode-operand 0 operands) (specifier-type type))) (t (values nil nil)))))))) (defun rewrite-acode-form (form type) (when (acode-p form) (let* ((op (acode-operator form)) (rest (acode-operands form)) (rewrite (svref *acode-rewrite-functions* (logand op operator-id-mask)))) (when rewrite (let* ((new (cons op rest)) (type-cons (list type new))) (setf (car form) (%nx1-operator type-asserted-form) (cdr form) type-cons) (funcall rewrite type-cons new)))))) (defun acode-constant-fold-numeric-binop (type-cons whole form1 form2 function) (rewrite-acode-form form1 t) (rewrite-acode-form form2 t) (let* ((v1 (acode-xxx-form-p form1 'number)) (v2 (acode-xxx-form-p form2 'number)) (val (and v1 v2 (ignore-errors (funcall function v1 v2))))) (when val (setf (car whole) (if (typep val *nx-target-fixnum-type*) (%nx1-operator fixnum) (%nx1-operator immediate)) (cadr whole) val (cddr whole) nil (car type-cons) (if (typep val 'integer) `(integer ,val ,val) (type-of val))) val))) (defun acode-rewrite-decls (decls) (if (fixnump decls) (locally (declare (fixnum decls)) (setq *acode-rewrite-tail-allow* (neq 0 (%ilogand2 $decl_tailcalls decls)) *acode-rewrite-open-code-inline* (neq 0 (%ilogand2 $decl_opencodeinline decls)) *acode-rewrite-full-safety* (neq 0 (%ilogand2 $decl_full_safety decls)) *acode-rewrite-reckless* (neq 0 (%ilogand2 $decl_unsafe decls)) *acode-rewrite-trust-declarations* (neq 0 (%ilogand2 $decl_trustdecls decls)))))) (defmacro with-acode-declarations (declsform &body body) `(let* ((*acode-rewrite-tail-allow* *acode-rewrite-tail-allow*) (*acode-rewrite-reckless* *acode-rewrite-reckless*) (*acode-rewrite-open-code-inline* *acode-rewrite-open-code-inline*) (*acode-rewrite-trust-declarations* *acode-rewrite-trust-declarations*) (*acode-rewrite-full-safety* *acode-rewrite-full-safety*)) (acode-rewrite-decls ,declsform) ,@body)) (defun acode-maybe-punt-var (var initform) (let* ((bits (nx-var-bits var))) (declare (fixnum bits)) (cond ((and (logbitp $vbitpuntable var) (not (logbitp $vbitpunted var))) (nx-set-var-bits var (logior (ash 1 $vbitpunted) bits)) (rewrite-acode-form initform (or (var-inittype var) t)) (nx2-replace-var-refs var initform) (setf (var-ea var) initform)) (t (rewrite-acode-form initform t))))) (defun acode-type-merge (type-cons derived) (let* ((asserted (car type-cons)) (intersection (ignore-errors (type-specifier (specifier-type `(and ,asserted ,derived)))))) (when intersection (setf (car type-cons) intersection)))) #|| (defun acode-set-immediate-type (type-cons acode-expr) (let* ((type (cond ((nx-null acode-expr) 'null) ((nx-t acode-expr) '(eql t)) (( ||# (def-acode-rewrite acode-rewrite-lambda lambda-list type-cons (req opt rest keys auxen body p2-decls &optional code-note) (declare (ignore code-note req rest)) (with-acode-declarations p2-decls (dolist (optinit (cadr opt)) (rewrite-acode-form optinit t)) (dolist (keyinit (nth 3 keys)) (rewrite-acode-form keyinit t)) (do* ((auxvars (car auxen) (cdr auxvars)) (auxvals (cadr auxen) (cdr auxvals))) ((null auxvars)) (acode-maybe-punt-var (car auxvars) (car auxvals))) (rewrite-acode-form body (car type-cons)) (acode-type-merge type-cons (acode-form-type body *acode-rewrite-trust-declarations*)))) (def-acode-rewrite acode-rewrite-progn progn type-cons (&rest forms) (do* ((form (pop forms) (pop forms))) ((null forms)) (if forms (rewrite-acode-form form t) (progn (rewrite-acode-form form (car type-cons)) (acode-type-merge type-cons (acode-form-type form *acode-rewrite-trust-declarations*)))))) (def-acode-rewrite acode-rewrite-prog1 prog1 type-cons (first &rest others) (rewrite-acode-form first (car type-cons)) (dolist (other others) (rewrite-acode-form other t)) (acode-type-merge type-cons (acode-form-type first *acode-rewrite-trust-declarations*))) (def-acode-rewrite acode-rewrite-%slot-ref %slot-ref type-cons (instance idx) (rewrite-acode-form instance t) (rewrite-acode-form idx t)) (def-acode-rewrite acode-rewrite-svref (%svref svref) type-cons (&whole w vector idx) (rewrite-acode-form vector t) (rewrite-acode-form idx t) (let* ((cv (acode-constant-p vector))) (when (if (eql (car w) (%nx1-operator svref)) (typep cv 'simple-vector) (gvectorp cv)) (let* ((cidx (acode-fixnum-form-p idx))) (when (and (typep cidx 'fixnum) (>= (the fixnum cidx) 0) (< (the fixnum cidx) (the fixnum (uvsize cv)))) (let* ((val (%svref cv cidx))) (setf (car w) (if (nx1-target-fixnump val) (%nx1-operator fixnum) (%nx1-operator immediate)) (cadr w) val (cddr w) nil) (acode-type-merge type-cons (type-of val)))))))) (def-acode-rewrite acode-rewrite-%sbchar %sbchar type-cons (&whole w string idx) (rewrite-acode-form string t) (rewrite-acode-form idx t) (let* ((cv (acode-constant-p string))) (when (typep cv 'simple-string) (let* ((cidx (acode-fixnum-form-p idx))) (when (and (typep cidx 'fixnum) (>= (the fixnum cidx) 0) (< (the fixnum cidx) (the fixnum (length cv)))) (let* ((val (%schar cv cidx))) (setf (car w) (%nx1-operator immediate) (cadr w) val (cddr w) nil) (acode-type-merge type-cons 'character))))))) (def-acode-rewrite acode-rewrite-svset (%svset svset) type-cons (vector idx value) (rewrite-acode-form vector t) (rewrite-acode-form idx t) (rewrite-acode-form value (car type-cons)) (acode-type-merge type-cons (acode-form-type value *acode-rewrite-trust-declarations*))) (def-acode-rewrite acode-rewrite-consp consp type-cons (&whole w cc thing) (rewrite-acode-form thing t) (multiple-value-bind (cthing constantp) (acode-constant-p thing) (if constantp (let* ((consp (consp cthing)) (ccode (cadr cc)) (val (if (eq ccode :eq) (not (not consp)) (not consp)))) (setf (car w) (if val (%nx1-operator t) (%nx1-operator nil)) (cdr w) nil))))) (def-acode-rewrite acode-rewrite-cons cons type-cons (x y) (rewrite-acode-form x t) (rewrite-acode-form y t) (acode-type-merge type-cons 'cons)) (def-acode-rewrite acode-rewrite-rplacx (%rplaca %rplacd rplaca rplacd) type-cons (cell val) (rewrite-acode-form cell t) (rewrite-acode-form val t) (acode-type-merge type-cons 'cons)) (def-acode-rewrite acode-rewrite-set-cxr (set-car set-cdr) type-cons (cell val) (rewrite-acode-form cell t) (rewrite-acode-form val t) (acode-type-merge type-cons (acode-form-type val *acode-rewrite-trust-declarations*))) (def-acode-rewrite acode-rewrite-cxr (%car %cdr car cdr) type-cons (cell) (rewrite-acode-form cell t)) (def-acode-rewrite acode-rewrite-vector vector type-cons (arglist) (dolist (f arglist) (rewrite-acode-form f t)) (acode-type-merge type-cons 'simple-vector)) (def-acode-rewrite acode-rewrite-%gvector %gvector type-cons (arglist) (let* ((all-args (append (car arglist) (reverse (cadr arglist))))) (dolist (arg all-args) (rewrite-acode-form arg t)) ;; Could try to map constant subtag to type here )) (def-acode-rewrite acode-rewrite-char-code (%char-code char-code) type-cons (&whole w c) (rewrite-acode-form c t) (let* ((char (acode-constant-p c))) (when char (let* ((code (char-code char))) (setf (car w) (%nx1-operator fixnum) (cadr w) code (cddr w) nil))) (acode-type-merge type-cons 'valid-char-code))) (def-acode-rewrite acode-rewrite-%ilogior2 %ilogior2 type-cons (&whole w x y) (acode-constant-fold-numeric-binop type-cons w x y 'logior) (acode-type-merge type-cons `(or ,(acode-form-type x *acode-rewrite-trust-declarations*) ,(acode-form-type y *acode-rewrite-trust-declarations*)))) (def-acode-rewrite acode-rewrite-%ilogand2 %ilogand2 type-cons (&whole w x y) (acode-constant-fold-numeric-binop type-cons w x y 'logand) (acode-type-merge type-cons `(and ,(acode-form-type x *acode-rewrite-trust-declarations*) ,(acode-form-type y *acode-rewrite-trust-declarations*)))) (def-acode-rewrite acode-rewrite-%ilogxor %ilogxor2 type-cons (&whole w x y) (acode-constant-fold-numeric-binop type-cons w x y 'logxor)) (def-acode-rewrite acode-rewrite-%ineg %ineg type-cons (&whole w x) (rewrite-acode-form x 'fixnum) (let* ((val (acode-fixnum-form-p x)) (negated (if val (- val)))) (if negated (setf (acode-operator w) (if (typep negated *nx-target-fixnum-type*) (%nx1-operator fixnum) (%nx1-operator immediate)) (cadr w) negated (cddr w) nil))))