(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))))
(eq (defined-fun-functional defined-fun) fun))
(remhash name *free-funs*))))))
+;;; Return functional for DEFINED-FUN which has been converted in policy
+;;; corresponding to the current one, or NIL if no such functional exists.
+(defun defined-fun-functional (defined-fun)
+ (let ((policy (lexenv-%policy *lexenv*)))
+ (dolist (functional (defined-fun-functionals defined-fun))
+ (when (equal policy (lexenv-%policy (functional-lexenv functional)))
+ (return functional)))))
+
;;; Do stuff to delete the semantic attachments of a REF node. When
;;; this leaves zero or one reference, we do a type dispatch off of
;;; the leaf to determine if a special action is appropriate.
(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))))))))