(eq (ctran-next it) dest))
(t (eq (block-start (first (block-succ (node-block node))))
(node-prev dest))))))
+
+;;; Return true if LVAR destination is executed after node with only
+;;; uninteresting nodes intervening.
+;;;
+;;; Uninteresting nodes are nodes in the same block which are either
+;;; REFs, external CASTs to the same destination, or known combinations
+;;; that never unwind.
+(defun almost-immediately-used-p (lvar node)
+ (declare (type lvar lvar)
+ (type node node))
+ (aver (eq (node-lvar node) lvar))
+ (let ((dest (lvar-dest lvar)))
+ (tagbody
+ :next
+ (let ((ctran (node-next node)))
+ (cond (ctran
+ (setf node (ctran-next ctran))
+ (if (eq node dest)
+ (return-from almost-immediately-used-p t)
+ (typecase node
+ (ref
+ (go :next))
+ (cast
+ (when (and (eq :external (cast-type-check node))
+ (eq dest (node-dest node)))
+ (go :next)))
+ (combination
+ ;; KLUDGE: Unfortunately we don't have an attribute for
+ ;; "never unwinds", so we just special case
+ ;; %ALLOCATE-CLOSURES: it is easy to run into with eg.
+ ;; FORMAT and a non-constant first argument.
+ (when (eq '%allocate-closures (combination-fun-source-name node nil))
+ (go :next))))))
+ (t
+ (when (eq (block-start (first (block-succ (node-block node))))
+ (node-prev dest))
+ (return-from almost-immediately-used-p t))))))))
\f
;;;; lvar substitution
(setf (lvar-dynamic-extent old) nil)
(unless (lvar-dynamic-extent new)
(setf (lvar-dynamic-extent new) it)
- (setf (cleanup-info it) (substitute new old (cleanup-info it)))))
+ (setf (cleanup-info it) (subst new old (cleanup-info it)))))
(when (lvar-dynamic-extent new)
(do-uses (node new)
(node-ends-block node))))
(awhen (node-lvar node)
(lvar-dynamic-extent it)))
+(defun flushable-combination-p (call)
+ (declare (combination call))
+ (let ((kind (combination-kind call))
+ (info (combination-fun-info call)))
+ (when (and (eq kind :known) (fun-info-p info))
+ (let ((attr (fun-info-attributes info)))
+ (when (and (not (ir1-attributep attr call))
+ ;; FIXME: For now, don't consider potentially flushable
+ ;; calls flushable when they have the CALL attribute.
+ ;; Someday we should look at the functional args to
+ ;; determine if they have any side effects.
+ (if (policy call (= safety 3))
+ (ir1-attributep attr flushable)
+ (ir1-attributep attr unsafely-flushable)))
+ t)))))
+
+(defun note-no-stack-allocation (lvar &key flush)
+ (do-uses (use (principal-lvar lvar))
+ (unless (or
+ ;; Don't complain about not being able to stack allocate constants.
+ (and (ref-p use) (constant-p (ref-leaf use)))
+ ;; If we're flushing, don't complain if we can flush the combination.
+ (and flush (combination-p use) (flushable-combination-p use)))
+ (let ((*compiler-error-context* use))
+ (compiler-notify "could not stack allocate the result of ~S"
+ (find-original-source (node-source-path use)))))))
+
+
(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))
(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)
+ (when 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)
- (awhen (fun-info-stack-allocate-result (combination-fun-info use))
- (funcall it use dx))))
+ (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)
(lambda-return clambda)))
(result-use (when (return-p creturn)
(principal-lvar-use (return-result creturn)))))
- (when result-use
- (if (known-dx-combination-p result-use dx)
- (combination-args-flow-cleanly-p use result-use dx)
- (dx-combination-p result-use dx)))))
- t))
+ ;; 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)
(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.
(defun flush-dest (lvar)
(declare (type (or lvar null) lvar))
(unless (null lvar)
+ (when (lvar-dynamic-extent lvar)
+ (note-no-stack-allocation lvar :flush t))
(setf (lvar-dest lvar) nil)
(flush-lvar-externally-checkable-type lvar)
(do-uses (use lvar)
;;; arguments.
(defun splice-fun-args (lvar fun num-args)
#!+sb-doc
- "If LVAR is a call to FUN with NUM-ARGS args, change those arguments
- to feed directly to the LVAR-DEST of LVAR, which must be a
- combination."
+ "If LVAR is a call to FUN with NUM-ARGS args, change those arguments to feed
+directly to the LVAR-DEST of LVAR, which must be a combination. If FUN
+is :ANY, the function name is not checked."
(declare (type lvar lvar)
(type symbol fun)
(type index num-args))
(unless (combination-p inside)
(give-up-ir1-transform))
(let ((inside-fun (combination-fun inside)))
- (unless (eq (lvar-fun-name inside-fun) fun)
+ (unless (or (eq fun :any)
+ (eq (lvar-fun-name inside-fun) fun))
(give-up-ir1-transform))
(let ((inside-args (combination-args inside)))
(unless (= (length inside-args) num-args)
(combination-kind inside) :known)
(setf (node-derived-type inside) *wild-type*)
(flush-dest lvar)
- (values))))))
+ inside-args)))))
+
+;;; Eliminate keyword arguments from the call (leaving the
+;;; parameters in place.
+;;;
+;;; (FOO ... :BAR X :QUUX Y)
+;;; becomes
+;;; (FOO ... X Y)
+;;;
+;;; SPECS is a list of (:KEYWORD PARAMETER) specifications.
+;;; Returns the list of specified parameters names in the
+;;; order they appeared in the call. N-POSITIONAL is the
+;;; number of positional arguments in th call.
+(defun eliminate-keyword-args (call n-positional specs)
+ (let* ((specs (copy-tree specs))
+ (all (combination-args call))
+ (new-args (reverse (subseq all 0 n-positional)))
+ (key-args (subseq all n-positional))
+ (parameters nil)
+ (flushed-keys nil))
+ (loop while key-args
+ do (let* ((key (pop key-args))
+ (val (pop key-args))
+ (keyword (if (constant-lvar-p key)
+ (lvar-value key)
+ (give-up-ir1-transform)))
+ (spec (or (assoc keyword specs :test #'eq)
+ (give-up-ir1-transform))))
+ (push val new-args)
+ (push key flushed-keys)
+ (push (second spec) parameters)
+ ;; In case of duplicate keys.
+ (setf (second spec) (gensym))))
+ (dolist (key flushed-keys)
+ (flush-dest key))
+ (setf (combination-args call) (reverse new-args))
+ (reverse parameters)))
(defun extract-fun-args (lvar fun num-args)
(declare (type lvar lvar)
((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)))))
+ ;; 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 bit-vector
+ ;; in the cross-compiler, we coalesce
+ ;; all strings with the same contents,
+ ;; because we will end up dumping them
+ ;; as base-strings anyway. In the
+ ;; real compiler, we're not allowed to
+ ;; coalesce regardless of string
+ ;; specialized element type, so we
+ ;; KLUDGE by coalescing only character
+ ;; strings (the common case) and
+ ;; punting on the other types.
+ #+sb-xc-host
+ string
+ #-sb-xc-host
+ (vector character))))))
(coalescep (x)
(if faslp (file-coalesce-p x) (core-coalesce-p x))))
(if (and (boundp '*constants*) (coalescep object))
;;; Return the source name of a combination. (This is an idiom
;;; which was used in CMU CL. I gather it always works. -- WHN)
-(defun combination-fun-source-name (combination)
- (let ((ref (lvar-uses (combination-fun combination))))
- (leaf-source-name (ref-leaf ref))))
+(defun combination-fun-source-name (combination &optional (errorp t))
+ (let ((leaf (ref-leaf (lvar-uses (combination-fun combination)))))
+ (when (or errorp (leaf-has-source-name-p leaf))
+ (leaf-source-name leaf))))
;;; Return the COMBINATION node that is the call to the LET FUN.
(defun let-combination (fun)
(eq (global-var-kind leaf) :global-function)
(not (null (member (leaf-source-name leaf) names
:test #'equal))))))))
+
+(defun lvar-matches (lvar &key fun-names arg-count)
+ (let ((use (lvar-use lvar)))
+ (and (combination-p use)
+ (or (not fun-names)
+ (member (combination-fun-source-name use)
+ fun-names :test #'eq))
+ (or (not arg-count)
+ (= arg-count (length (combination-args use)))))))