(awhen (node-lvar node)
(lvar-dynamic-extent it)))
-(declaim (ftype (sfunction (node &optional (or null component)) boolean)
- use-good-for-dx-p))
-(declaim (ftype (sfunction (lvar &optional (or null component)) boolean)
- lvar-good-for-dx-p))
-(defun use-good-for-dx-p (use &optional component)
+(declaim (ftype (sfunction (node (member nil t :truly) &optional (or null component))
+ boolean) use-good-for-dx-p))
+(declaim (ftype (sfunction (lvar (member nil t :truly) &optional (or null component))
+ boolean) lvar-good-for-dx-p))
+(defun use-good-for-dx-p (use dx &optional component)
;; FIXME: Can casts point to LVARs in other components?
- ;; RECHECK-DYNAMIC-EXTENT-LVARS assumes that they can't -- that
- ;; is, that the PRINCIPAL-LVAR is always in the same component
- ;; as the original one. It would be either good to have an
- ;; explanation of why casts don't point across components, or an
- ;; explanation of when they do it. ...in the meanwhile AVER that
- ;; our expactation holds true.
+ ;; RECHECK-DYNAMIC-EXTENT-LVARS assumes that they can't -- that is, that the
+ ;; PRINCIPAL-LVAR is always in the same component as the original one. It
+ ;; would be either good to have an explanation of why casts don't point
+ ;; across components, or an explanation of when they do it. ...in the
+ ;; meanwhile AVER that our assumption holds true.
(aver (or (not component) (eq component (node-component use))))
- (or (and (combination-p use)
- (eq (combination-kind use) :known)
- (awhen (fun-info-stack-allocate-result
- (combination-fun-info use))
- (funcall it use))
- t)
+ (or (dx-combination-p use dx)
(and (cast-p use)
(not (cast-type-check use))
- (lvar-good-for-dx-p (cast-value use) component)
- t)))
+ (lvar-good-for-dx-p (cast-value use) dx component))
+ (and (trivial-lambda-var-ref-p use)
+ (let ((uses (lvar-uses (trivial-lambda-var-ref-lvar use))))
+ (or (eq use uses)
+ (lvar-good-for-dx-p (trivial-lambda-var-ref-lvar use) dx component))))))
-(defun lvar-good-for-dx-p (lvar &optional component)
+(defun lvar-good-for-dx-p (lvar dx &optional component)
(let ((uses (lvar-uses lvar)))
(if (listp uses)
(every (lambda (use)
- (use-good-for-dx-p use component))
+ (use-good-for-dx-p use dx component))
uses)
- (use-good-for-dx-p uses component))))
+ (use-good-for-dx-p uses dx component))))
+
+(defun known-dx-combination-p (use dx)
+ (and (eq (combination-kind use) :known)
+ (awhen (fun-info-stack-allocate-result (combination-fun-info use))
+ (funcall it use dx))))
+
+(defun dx-combination-p (use dx)
+ (and (combination-p use)
+ (or
+ ;; Known, and can do DX.
+ (known-dx-combination-p use dx)
+ ;; Possibly a not-yet-eliminated lambda which ends up returning the
+ ;; results of an actual known DX combination.
+ (let* ((fun (combination-fun use))
+ (ref (principal-lvar-use fun))
+ (clambda (when (ref-p ref)
+ (ref-leaf ref)))
+ (creturn (when (lambda-p clambda)
+ (lambda-return clambda)))
+ (result-use (when (return-p creturn)
+ (principal-lvar-use (return-result creturn)))))
+ ;; FIXME: We should be able to deal with multiple uses here as well.
+ (and (dx-combination-p result-use dx)
+ (combination-args-flow-cleanly-p use result-use dx))))))
+
+(defun combination-args-flow-cleanly-p (combination1 combination2 dx)
+ (labels ((recurse (combination)
+ (or (eq combination combination2)
+ (if (known-dx-combination-p combination dx)
+ (let ((dest (lvar-dest (combination-lvar combination))))
+ (and (combination-p dest)
+ (recurse dest)))
+ (let* ((fun1 (combination-fun combination))
+ (ref1 (principal-lvar-use fun1))
+ (clambda1 (when (ref-p ref1) (ref-leaf ref1))))
+ (when (lambda-p clambda1)
+ (dolist (var (lambda-vars clambda1) t)
+ (dolist (var-ref (lambda-var-refs var))
+ (let ((dest (lvar-dest (ref-lvar var-ref))))
+ (unless (and (combination-p dest) (recurse dest))
+ (return-from combination-args-flow-cleanly-p nil)))))))))))
+ (recurse combination1)))
+
+(defun trivial-lambda-var-ref-p (use)
+ (and (ref-p use)
+ (let ((var (ref-leaf use)))
+ ;; lambda-var, no SETS
+ (when (and (lambda-var-p var) (not (lambda-var-sets var)))
+ (let ((home (lambda-var-home var))
+ (refs (lambda-var-refs var)))
+ ;; bound by a system lambda, no other REFS
+ (when (and (lambda-system-lambda-p home)
+ (eq use (car refs)) (not (cdr refs)))
+ ;; the LAMBDA this var is bound by has only a single REF, going
+ ;; to a combination
+ (let* ((lambda-refs (lambda-refs home))
+ (primary (car lambda-refs)))
+ (and (ref-p primary)
+ (not (cdr lambda-refs))
+ (combination-p (lvar-dest (ref-lvar primary)))))))))))
+
+(defun trivial-lambda-var-ref-lvar (use)
+ (let* ((this (ref-leaf use))
+ (home (lambda-var-home this)))
+ (multiple-value-bind (fun vars)
+ (values home (lambda-vars home))
+ (let* ((combination (lvar-dest (ref-lvar (car (lambda-refs fun)))))
+ (args (combination-args combination)))
+ (assert (= (length vars) (length args)))
+ (loop for var in vars
+ for arg in args
+ when (eq var this)
+ return arg)))))
(declaim (inline block-to-be-deleted-p))
(defun block-to-be-deleted-p (block)
(let* ((block (node-block node))
(start (node-next node))
(last (block-last block)))
+ (check-type last node)
(unless (eq last node)
(aver (and (eq (ctran-kind start) :inside-block)
(not (block-delete-p block))))
;;; Return a LEAF which represents the specified constant object. If
;;; the object is not in *CONSTANTS*, then we create a new constant
-;;; LEAF and enter it.
-(defun find-constant (object)
- (if (typep object
- ;; FIXME: What is the significance of this test? ("things
- ;; that are worth uniquifying"?)
- '(or symbol number character instance))
- (or (gethash object *constants*)
- (setf (gethash object *constants*)
- (make-constant :value object
- :%source-name '.anonymous.
- :type (ctype-of object)
- :where-from :defined)))
- (make-constant :value object
- :%source-name '.anonymous.
- :type (ctype-of object)
- :where-from :defined)))
+;;; LEAF and enter it. If we are producing a fasl file, make sure that
+;;; MAKE-LOAD-FORM gets used on any parts of the constant that it
+;;; needs to be.
+;;;
+;;; We are allowed to coalesce things like EQUAL strings and bit-vectors
+;;; when file-compiling, but not when using COMPILE.
+(defun find-constant (object &optional (name nil namep))
+ (let ((faslp (producing-fasl-file)))
+ (labels ((make-it ()
+ (when faslp
+ (if namep
+ (maybe-emit-make-load-forms object name)
+ (maybe-emit-make-load-forms object)))
+ (make-constant object))
+ (core-coalesce-p (x)
+ ;; True for things which retain their identity under EQUAL,
+ ;; so we can safely share the same CONSTANT leaf between
+ ;; multiple references.
+ (or (typep x '(or symbol number character))
+ ;; Amusingly enough, we see CLAMBDAs --among other things--
+ ;; here, from compiling things like %ALLOCATE-CLOSUREs forms.
+ ;; No point in stuffing them in the hash-table.
+ (and (typep x 'instance)
+ (not (or (leaf-p x) (node-p x))))))
+ (file-coalesce-p (x)
+ ;; CLHS 3.2.4.2.2: We are also allowed to coalesce various
+ ;; other things when file-compiling.
+ (or (core-coalesce-p x)
+ (if (consp x)
+ (if (eq +code-coverage-unmarked+ (cdr x))
+ ;; These are already coalesced, and the CAR should
+ ;; always be OK, so no need to check.
+ t
+ (unless (maybe-cyclic-p x) ; safe for EQUAL?
+ (do ((y x (cdr y)))
+ ((atom y) (file-coalesce-p y))
+ (unless (file-coalesce-p (car y))
+ (return nil)))))
+ ;; We *could* coalesce base-strings as well, but we'd need
+ ;; a separate hash-table for that, since we are not allowed to
+ ;; coalesce base-strings with non-base-strings.
+ (typep x '(or (vector character) bit-vector)))))
+ (coalescep (x)
+ (if faslp (file-coalesce-p x) (core-coalesce-p x))))
+ (if (and (boundp '*constants*) (coalescep object))
+ (or (gethash object *constants*)
+ (setf (gethash object *constants*)
+ (make-it)))
+ (make-it)))))
\f
;;; Return true if VAR would have to be closed over if environment
;;; analysis ran now (i.e. if there are any uses that have a different
(setf (block-reoptimize (node-block node)) t)
(reoptimize-component (node-component node) :maybe)))))))
-;;; True if LVAR is for 'NAME, or #'NAME (global, not local)
-(defun lvar-for-named-function (lvar name)
- (if (constant-lvar-p lvar)
- (eq name (lvar-value lvar))
- (let ((use (lvar-uses lvar)))
- (and (not (listp use))
- (ref-p use)
- (let ((leaf (ref-leaf use)))
- (and (global-var-p leaf)
- (eq :global-function (global-var-kind leaf))
- (eq name (leaf-source-name leaf))))))))
+;;; Return true if LVAR's only use is a non-NOTINLINE reference to a
+;;; global function with one of the specified NAMES.
+(defun lvar-fun-is (lvar names)
+ (declare (type lvar lvar) (list names))
+ (let ((use (lvar-uses lvar)))
+ (and (ref-p use)
+ (let ((leaf (ref-leaf use)))
+ (and (global-var-p leaf)
+ (eq (global-var-kind leaf) :global-function)
+ (not (null (member (leaf-source-name leaf) names
+ :test #'equal))))))))