+ (lambda-physenv (node-home-lambda node)))
+#!-sb-fluid (declaim (inline node-dest))
+(defun node-dest (node)
+ (awhen (node-lvar node) (lvar-dest it)))
+
+#!-sb-fluid (declaim (inline node-stack-allocate-p))
+(defun node-stack-allocate-p (node)
+ (awhen (node-lvar node)
+ (lvar-dynamic-extent it)))
+
+(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 assumption holds true.
+ (aver (or (not component) (eq component (node-component use))))
+ (or (dx-combination-p use dx)
+ (and (cast-p use)
+ (not (cast-type-check use))
+ (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 dx &optional component)
+ (let ((uses (lvar-uses lvar)))
+ (if (listp uses)
+ (every (lambda (use)
+ (use-good-for-dx-p use dx component))
+ uses)
+ (use-good-for-dx-p uses dx component))))
+
+(defun known-dx-combination-p (use dx)
+ (and (eq (combination-kind use) :known)
+ (let ((info (combination-fun-info use)))
+ (or (awhen (fun-info-stack-allocate-result info)
+ (funcall it use dx))
+ (awhen (fun-info-result-arg info)
+ (let ((args (combination-args use)))
+ (lvar-good-for-dx-p (if (zerop it)
+ (car args)
+ (nth it args))
+ 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)
+ (or (block-delete-p block)
+ (eq (functional-kind (block-home-lambda block)) :deleted)))
+
+;;; Checks whether NODE is in a block to be deleted
+(declaim (inline node-to-be-deleted-p))
+(defun node-to-be-deleted-p (node)
+ (block-to-be-deleted-p (node-block node)))
+
+(declaim (ftype (sfunction (clambda) cblock) lambda-block))