X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Flocall.lisp;h=bf6507b29d60c3f3806fc739bf00ea127b4fe6e5;hb=57e21c4b62e8c1a1ee7ef59ed2abb0c864fb06bc;hp=2a2bd492acf4846a99e4aa266fb776417bad7e41;hpb=422b88abf96f4842a3d0999cd3b80d96f5a153d6;p=sbcl.git diff --git a/src/compiler/locall.lisp b/src/compiler/locall.lisp index 2a2bd49..bf6507b 100644 --- a/src/compiler/locall.lisp +++ b/src/compiler/locall.lisp @@ -31,20 +31,16 @@ ;;; the remaining args still match up with their vars. ;;; ;;; We also apply the declared variable type assertion to the argument -;;; continuations. +;;; lvars. (defun propagate-to-args (call fun) (declare (type combination call) (type clambda fun)) - (do ((args (basic-combination-args call) (cdr args)) - (vars (lambda-vars fun) (cdr vars))) - ((null args)) - (let ((arg (car args)) - (var (car vars))) - (cond ((leaf-refs var) - (assert-continuation-type arg (leaf-type var))) - (t - (flush-dest arg) - (setf (car args) nil))))) - + (loop with policy = (lexenv-policy (node-lexenv call)) + for args on (basic-combination-args call) + and var in (lambda-vars fun) + do (assert-lvar-type (car args) (leaf-type var) policy) + do (unless (leaf-refs var) + (flush-dest (car args)) + (setf (car args) nil))) (values)) ;;; This function handles merging the tail sets if CALL is potentially @@ -58,11 +54,11 @@ ;;; We destructively modify the set for the calling function to ;;; represent both, and then change all the functions in callee's set ;;; to reference the first. If we do merge, we reoptimize the -;;; RETURN-RESULT continuation to cause IR1-OPTIMIZE-RETURN to -;;; recompute the tail set type. +;;; RETURN-RESULT lvar to cause IR1-OPTIMIZE-RETURN to recompute the +;;; tail set type. (defun merge-tail-sets (call &optional (new-fun (combination-lambda call))) (declare (type basic-combination call) (type clambda new-fun)) - (let ((return (continuation-dest (node-cont call)))) + (let ((return (node-dest call))) (when (return-p return) (let ((call-set (lambda-tail-set (node-home-lambda call))) (fun-set (lambda-tail-set new-fun))) @@ -72,7 +68,7 @@ (setf (lambda-tail-set fun) call-set)) (setf (tail-set-funs call-set) (nconc (tail-set-funs call-set) funs))) - (reoptimize-continuation (return-result return)) + (reoptimize-lvar (return-result return)) t))))) ;;; Convert a combination into a local call. We PROPAGATE-TO-ARGS, set @@ -91,6 +87,10 @@ (declare (type ref ref) (type combination call) (type clambda fun)) (propagate-to-args call fun) (setf (basic-combination-kind call) :local) + (unless (call-full-like-p call) + (dolist (arg (basic-combination-args call)) + (when arg + (flush-lvar-externally-checkable-type arg)))) (pushnew fun (lambda-calls-or-closes (node-home-lambda call))) (merge-tail-sets call fun) (change-ref-leaf ref fun) @@ -111,9 +111,9 @@ ;;; ;;; If there is a &MORE arg, then there are a couple of optimizations ;;; that we make (more for space than anything else): -;;; -- If MIN-ARGS is 0, then we make the more entry a T clause, since +;;; -- If MIN-ARGS is 0, then we make the more entry a T clause, since ;;; no argument count error is possible. -;;; -- We can omit the = clause for the last entry-point, allowing the +;;; -- We can omit the = clause for the last entry-point, allowing the ;;; case of 0 more args to fall through to the more entry. ;;; ;;; We don't bother to policy conditionalize wrong arg errors in @@ -133,21 +133,11 @@ (temps (make-gensym-list (length (lambda-vars fun))))) `(lambda (,n-supplied ,@temps) (declare (type index ,n-supplied)) - ,(if (policy *lexenv* (zerop safety)) + ,(if (policy *lexenv* (zerop verify-arg-count)) `(declare (ignore ,n-supplied)) `(%verify-arg-count ,n-supplied ,nargs)) (locally - ;; KLUDGE: The intent here is to enable tail recursion - ;; optimization, since leaving frames for wrapper - ;; functions like this on the stack is actually more - ;; annoying than helpful for debugging. Unfortunately - ;; trying to express this by messing with the - ;; ANSI-standard declarations is a little awkward, since - ;; no matter how we do it we'll tend to have side-effects - ;; on things like SPEED-vs.-SAFETY comparisons. Perhaps - ;; it'd be better to define a new SB-EXT:TAIL-RECURSIVELY - ;; declaration and use that? -- WHN 2002-07-08 - (declare (optimize (speed 2) (debug 1))) + (declare (optimize (merge-tail-calls 3))) (%funcall ,fun ,@temps))))) (optional-dispatch (let* ((min (optional-dispatch-min-args fun)) @@ -156,11 +146,12 @@ (n-supplied (gensym)) (temps (make-gensym-list max))) (collect ((entries)) - (do ((eps (optional-dispatch-entry-points fun) (rest eps)) - (n min (1+ n))) - ((null eps)) - (entries `((= ,n-supplied ,n) - (%funcall ,(first eps) ,@(subseq temps 0 n))))) + ;; Force convertion of all entries + (optional-dispatch-entry-point-fun fun 0) + (loop for ep in (optional-dispatch-entry-points fun) + and n from min + do (entries `((= ,n-supplied ,n) + (%funcall ,(force ep) ,@(subseq temps 0 n))))) `(lambda (,n-supplied ,@temps) ;; FIXME: Make sure that INDEX type distinguishes between ;; target and host. (Probably just make the SB!XC:DEFTYPE @@ -175,11 +166,7 @@ `(multiple-value-bind (,n-context ,n-count) (%more-arg-context ,n-supplied ,max) (locally - ;; KLUDGE: As above, we're trying to - ;; enable tail recursion optimization and - ;; any other effects of this declaration - ;; are accidental. -- WHN 2002-07-08 - (declare (optimize (speed 2) (debug 1))) + (declare (optimize (merge-tail-calls 3))) (%funcall ,more ,@temps ,n-context ,n-count))))))) (t (%arg-count-error ,n-supplied))))))))) @@ -189,7 +176,7 @@ ;;; then associate this lambda with FUN as its XEP. After the ;;; conversion, we iterate over the function's associated lambdas, ;;; redoing local call analysis so that the XEP calls will get -;;; converted. +;;; converted. ;;; ;;; We set REANALYZE and REOPTIMIZE in the component, just in case we ;;; discover an XEP after the initial local call analyze pass. @@ -212,7 +199,7 @@ (locall-analyze-fun-1 fun)) (optional-dispatch (dolist (ep (optional-dispatch-entry-points fun)) - (locall-analyze-fun-1 ep)) + (locall-analyze-fun-1 (force ep))) (when (optional-dispatch-more-entry fun) (locall-analyze-fun-1 (optional-dispatch-more-entry fun))))) res))) @@ -232,11 +219,11 @@ (make-xep fun)))))) ;;; Attempt to convert all references to FUN to local calls. The -;;; reference must be the function for a call, and the function -;;; continuation must be used only once, since otherwise we cannot be -;;; sure what function is to be called. The call continuation would be -;;; multiply used if there is hairy stuff such as conditionals in the -;;; expression that computes the function. +;;; reference must be the function for a call, and the function lvar +;;; must be used only once, since otherwise we cannot be sure what +;;; function is to be called. The call lvar would be multiply used if +;;; there is hairy stuff such as conditionals in the expression that +;;; computes the function. ;;; ;;; If we cannot convert a reference, then we mark the referenced ;;; function as an entry-point, creating a new XEP if necessary. We @@ -250,11 +237,11 @@ (let ((refs (leaf-refs fun)) (first-time t)) (dolist (ref refs) - (let* ((cont (node-cont ref)) - (dest (continuation-dest cont))) + (let* ((lvar (node-lvar ref)) + (dest (when lvar (lvar-dest lvar)))) (cond ((and (basic-combination-p dest) - (eq (basic-combination-fun dest) cont) - (eq (continuation-use cont) ref)) + (eq (basic-combination-fun dest) lvar) + (eq (lvar-uses lvar) ref)) (convert-call-if-possible ref dest) @@ -331,7 +318,8 @@ ;; COMPONENT is the only one here. Let's make that explicit. (aver (= 1 (length (functional-components clambda)))) (aver (eql component (first (functional-components clambda)))) - (when (component-new-functionals component) + (when (or (component-new-functionals component) + (component-reanalyze-functionals component)) (setf did-something t) (locall-analyze-component component)))) (unless did-something @@ -348,27 +336,35 @@ (>= speed compilation-speed))) (not (eq (functional-kind (node-home-lambda call)) :external)) (inline-expansion-ok call)) - (multiple-value-bind (losing-local-functional converted-lambda) - (catch 'locall-already-let-converted - (with-ir1-environment-from-node call - (let ((*lexenv* (functional-lexenv original-functional))) - (values nil - (ir1-convert-lambda - (functional-inline-expansion original-functional) - :debug-name (debug-namify - "local inline ~A" - (leaf-debug-name - original-functional))))))) - (cond (losing-local-functional - (let ((*compiler-error-context* call)) - (compiler-note "couldn't inline expand because expansion ~ - calls this LET-converted local function:~ - ~% ~S" - (leaf-debug-name losing-local-functional))) - original-functional) - (t - (change-ref-leaf ref converted-lambda) - converted-lambda))) + (let* ((end (component-last-block (node-component call))) + (pred (block-prev end))) + (multiple-value-bind (losing-local-functional converted-lambda) + (catch 'locall-already-let-converted + (with-ir1-environment-from-node call + (let ((*lexenv* (functional-lexenv original-functional))) + (values nil + (ir1-convert-lambda + (functional-inline-expansion original-functional) + :debug-name (debug-namify + "local inline ~A" + (leaf-debug-name + original-functional))))))) + (cond (losing-local-functional + (let ((*compiler-error-context* call)) + (compiler-notify "couldn't inline expand because expansion ~ + calls this LET-converted local function:~ + ~% ~S" + (leaf-debug-name losing-local-functional))) + (loop for block = (block-next pred) then (block-next block) + until (eq block end) + do (setf (block-delete-p block) t)) + (loop for block = (block-next pred) then (block-next block) + until (eq block end) + do (delete-block block t)) + original-functional) + (t + (change-ref-leaf ref converted-lambda) + converted-lambda)))) original-functional)) ;;; Dispatch to the appropriate function to attempt to convert a call. @@ -427,9 +423,9 @@ (values)) ;;; Attempt to convert a multiple-value call. The only interesting -;;; case is a call to a function that Looks-Like-An-MV-Bind, has +;;; case is a call to a function that LOOKS-LIKE-AN-MV-BIND, has ;;; exactly one reference and no XEP, and is called with one values -;;; continuation. +;;; lvar. ;;; ;;; We change the call to be to the last optional entry point and ;;; change the call to be local. Due to our preconditions, the call @@ -438,25 +434,28 @@ ;;; optional defaulting code. ;;; ;;; We also use variable types for the called function to construct an -;;; assertion for the values continuation. +;;; assertion for the values lvar. ;;; ;;; See CONVERT-CALL for additional notes on MERGE-TAIL-SETS, etc. (defun convert-mv-call (ref call fun) (declare (type ref ref) (type mv-combination call) (type functional fun)) (when (and (looks-like-an-mv-bind fun) (not (functional-entry-fun fun)) - (= (length (leaf-refs fun)) 1) - (= (length (basic-combination-args call)) 1)) - (let ((ep (car (last (optional-dispatch-entry-points fun))))) + (singleton-p (leaf-refs fun)) + (singleton-p (basic-combination-args call))) + (let* ((*current-component* (node-component ref)) + (ep (optional-dispatch-entry-point-fun + fun (optional-dispatch-max-args fun)))) + (aver (= (optional-dispatch-min-args fun) 0)) (setf (basic-combination-kind call) :local) (pushnew ep (lambda-calls-or-closes (node-home-lambda call))) (merge-tail-sets call ep) (change-ref-leaf ref ep) - (assert-continuation-type + (assert-lvar-type (first (basic-combination-args call)) - (make-values-type :optional (mapcar #'leaf-type (lambda-vars ep)) - :rest *universal-type*)))) + (make-short-values-type (mapcar #'leaf-type (lambda-vars ep))) + (lexenv-policy (node-lexenv call))))) (values)) ;;; Attempt to convert a call to a lambda. If the number of args is @@ -466,8 +465,8 @@ (defun convert-lambda-call (ref call fun) (declare (type ref ref) (type combination call) (type clambda fun)) (let ((nargs (length (lambda-vars fun))) - (call-args (length (combination-args call)))) - (cond ((= call-args nargs) + (n-call-args (length (combination-args call)))) + (cond ((= n-call-args nargs) (convert-call ref call fun)) (t ;; FIXME: ANSI requires in "3.2.5 Exceptional Situations in the @@ -489,7 +488,7 @@ ;; file. So maybe it deserves a full warning anyway. (compiler-warn "function called with ~R argument~:P, but wants exactly ~R" - call-args nargs) + n-call-args nargs) (setf (basic-combination-kind call) :error))))) ;;;; &OPTIONAL, &MORE and &KEYWORD calls @@ -514,8 +513,9 @@ (setf (basic-combination-kind call) :error)) ((<= call-args max-args) (convert-call ref call - (elt (optional-dispatch-entry-points fun) - (- call-args min-args)))) + (let ((*current-component* (node-component ref))) + (optional-dispatch-entry-point-fun + fun (- call-args min-args))))) ((optional-dispatch-more-entry fun) (convert-more-call ref call fun)) (t @@ -545,14 +545,14 @@ (with-ir1-environment-from-node call (ir1-convert-lambda `(lambda ,vars - (declare (ignorable . ,ignores)) - (%funcall ,entry . ,args)) + (declare (ignorable ,@ignores)) + (%funcall ,entry ,@args)) :debug-name (debug-namify "hairy function entry ~S" - (continuation-fun-name + (lvar-fun-name (basic-combination-fun call))))))) (convert-call ref call new-fun) (dolist (ref (leaf-refs entry)) - (convert-call-if-possible ref (continuation-dest (node-cont ref)))))) + (convert-call-if-possible ref (lvar-dest (node-lvar ref)))))) ;;; Use CONVERT-HAIRY-FUN-ENTRY to convert a &MORE-arg call to a known ;;; function into a local call to the MAIN-ENTRY. @@ -578,6 +578,8 @@ (flame (policy call (or (> speed inhibit-warnings) (> space inhibit-warnings)))) (loser nil) + (allowp nil) + (allow-found nil) (temps (make-gensym-list max)) (more-temps (make-gensym-list (length more)))) (collect ((ignores) @@ -607,27 +609,38 @@ (do ((key more (cddr key)) (temp more-temps (cddr temp))) ((null key)) - (let ((cont (first key))) - (unless (constant-continuation-p cont) + (let ((lvar (first key))) + (unless (constant-lvar-p lvar) (when flame - (compiler-note "non-constant keyword in keyword call")) + (compiler-notify "non-constant keyword in keyword call")) (setf (basic-combination-kind call) :error) (return-from convert-more-call)) - (let ((name (continuation-value cont)) + (let ((name (lvar-value lvar)) (dummy (first temp)) (val (second temp))) + ;; FIXME: check whether KEY was supplied earlier + (when (and (eq name :allow-other-keys) (not allow-found)) + (let ((val (second key))) + (cond ((constant-lvar-p val) + (setq allow-found t + allowp (lvar-value val))) + (t (when flame + (compiler-notify "non-constant :ALLOW-OTHER-KEYS value")) + (setf (basic-combination-kind call) :error) + (return-from convert-more-call))))) (dolist (var (key-vars) (progn (ignores dummy val) - (setq loser name))) + (unless (eq name :allow-other-keys) + (setq loser name)))) (let ((info (lambda-var-arg-info var))) (when (eq (arg-info-key info) name) (ignores dummy) (supplied (cons var val)) (return))))))) - (when (and loser (not (optional-dispatch-allowp fun))) + (when (and loser (not (optional-dispatch-allowp fun)) (not allowp)) (compiler-warn "function called with unknown argument keyword ~S" loser) (setf (basic-combination-kind call) :error) @@ -636,7 +649,7 @@ (collect ((call-args)) (do ((var arglist (cdr var)) (temp temps (cdr temp))) - (()) + ((null var)) (let ((info (lambda-var-arg-info (car var)))) (if info (ecase (arg-info-kind info) @@ -674,8 +687,8 @@ ;;;; corresponding combination node, making the control transfer ;;;; explicit and allowing LETs to be mashed together into a single ;;;; block. The value of the LET is delivered directly to the -;;;; original continuation for the call, eliminating the need to -;;;; propagate information from the dummy result continuation. +;;;; original lvar for the call, eliminating the need to +;;;; propagate information from the dummy result lvar. ;;;; -- As far as IR1 optimization is concerned, it is interesting in ;;;; that there is only one expression that the variable can be bound ;;;; to, and this is easily substituted for. @@ -707,11 +720,8 @@ (join-components component clambda-component))) (let ((*current-component* component)) (node-ends-block call)) - ;; FIXME: Use DESTRUCTURING-BIND here, and grep for other - ;; uses of '=.*length' which could also be converted to use - ;; DESTRUCTURING-BIND or PROPER-LIST-OF-LENGTH-P. - (aver (= (length (block-succ call-block)) 1)) - (let ((next-block (first (block-succ call-block)))) + (destructuring-bind (next-block) + (block-succ call-block) (unlink-blocks call-block next-block) (link-blocks call-block bind-block) next-block))) @@ -766,10 +776,10 @@ ;; information. (setf (tail-set-info (lambda-tail-set clambda)) nil)) -;;; Handle the environment semantics of LET conversion. We add CLAMBDA -;;; and its LETs to LETs for the CALL's home function. We merge the -;;; calls for CLAMBDA with the calls for the home function, removing -;;; CLAMBDA in the process. We also merge the ENTRIES. +;;; Handle the PHYSENV semantics of LET conversion. We add CLAMBDA and +;;; its LETs to LETs for the CALL's home function. We merge the calls +;;; for CLAMBDA with the calls for the home function, removing CLAMBDA +;;; in the process. We also merge the ENTRIES. ;;; ;;; We also unlink the function head from the component head and set ;;; COMPONENT-REANALYZE to true to indicate that the DFO should be @@ -788,18 +798,20 @@ (depart-from-tail-set clambda) (let* ((home (node-home-lambda call)) - (home-env (lambda-physenv home))) + (home-physenv (lambda-physenv home))) + + (aver (not (eq home clambda))) ;; CLAMBDA belongs to HOME now. (push clambda (lambda-lets home)) (setf (lambda-home clambda) home) - (setf (lambda-physenv clambda) home-env) + (setf (lambda-physenv clambda) home-physenv) ;; All of CLAMBDA's LETs belong to HOME now. (let ((lets (lambda-lets clambda))) (dolist (let lets) - (setf (lambda-home let) home) - (setf (lambda-physenv let) home-env)) + (setf (lambda-home let) home) + (setf (lambda-physenv let) home-physenv)) (setf (lambda-lets home) (nconc lets (lambda-lets home)))) ;; CLAMBDA no longer has an independent existence as an entity ;; which has LETs. @@ -808,17 +820,17 @@ ;; HOME no longer calls CLAMBDA, and owns all of CLAMBDA's old ;; DFO dependencies. (setf (lambda-calls-or-closes home) - (delete clambda - (nunion (lambda-calls-or-closes clambda) - (lambda-calls-or-closes home)))) + (delete clambda + (nunion (lambda-calls-or-closes clambda) + (lambda-calls-or-closes home)))) ;; CLAMBDA no longer has an independent existence as an entity ;; which calls things or has DFO dependencies. (setf (lambda-calls-or-closes clambda) nil) ;; All of CLAMBDA's ENTRIES belong to HOME now. (setf (lambda-entries home) - (nconc (lambda-entries clambda) - (lambda-entries home))) + (nconc (lambda-entries clambda) + (lambda-entries home))) ;; CLAMBDA no longer has an independent existence as an entity ;; with ENTRIES. (setf (lambda-entries clambda) nil)) @@ -827,48 +839,29 @@ ;;; Handle the value semantics of LET conversion. Delete FUN's return ;;; node, and change the control flow to transfer to NEXT-BLOCK -;;; instead. Move all the uses of the result continuation to CALL's -;;; CONT. -;;; -;;; If the actual continuation is only used by the LET call, then we -;;; intersect the type assertion on the dummy continuation with the -;;; assertion for the actual continuation; in all other cases -;;; assertions on the dummy continuation are lost. -;;; -;;; We also intersect the derived type of the CALL with the derived -;;; type of all the dummy continuation's uses. This serves mainly to -;;; propagate TRULY-THE through LETs. +;;; instead. Move all the uses of the result lvar to CALL's lvar. (defun move-return-uses (fun call next-block) (declare (type clambda fun) (type basic-combination call) (type cblock next-block)) (let* ((return (lambda-return fun)) - (return-block (node-block return))) + (return-block (progn + (ensure-block-start (node-prev return)) + (node-block return)))) (unlink-blocks return-block (component-tail (block-component return-block))) (link-blocks return-block next-block) (unlink-node return) (delete-return return) (let ((result (return-result return)) - (cont (node-cont call)) - (call-type (node-derived-type call))) - (when (eq (continuation-use cont) call) - (assert-continuation-type cont (continuation-asserted-type result))) + (lvar (if (node-tail-p call) + (return-result (lambda-return (node-home-lambda call))) + (node-lvar call))) + (call-type (node-derived-type call))) (unless (eq call-type *wild-type*) - (do-uses (use result) - (derive-node-type use call-type))) - (substitute-continuation-uses cont result))) - (values)) - -;;; Change all CONT for all the calls to FUN to be the start -;;; continuation for the bind node. This allows the blocks to be -;;; joined if the caller count ever goes to one. -(defun move-let-call-cont (fun) - (declare (type clambda fun)) - (let ((new-cont (node-prev (lambda-bind fun)))) - (dolist (ref (leaf-refs fun)) - (let ((dest (continuation-dest (node-cont ref)))) - (delete-continuation-use dest) - (add-continuation-use dest new-cont)))) + ;; FIXME: Replace the call with unsafe CAST. -- APD, 2003-01-26 + (do-uses (use result) + (derive-node-type use call-type))) + (substitute-lvar-uses lvar result))) (values)) ;;; We are converting FUN to be a LET when the call is in a non-tail @@ -881,7 +874,7 @@ (dolist (called (lambda-calls-or-closes fun)) (when (lambda-p called) (dolist (ref (leaf-refs called)) - (let ((this-call (continuation-dest (node-cont ref)))) + (let ((this-call (node-dest ref))) (when (and this-call (node-tail-p this-call) (eq (node-home-lambda this-call) fun)) @@ -889,12 +882,11 @@ (ecase (functional-kind called) ((nil :cleanup :optional) (let ((block (node-block this-call)) - (cont (node-cont call))) - (ensure-block-start cont) + (lvar (node-lvar call))) (unlink-blocks block (first (block-succ block))) (link-blocks block next-block) - (delete-continuation-use this-call) - (add-continuation-use this-call cont))) + (aver (not (node-lvar this-call))) + (add-lvar-use this-call lvar))) (:deleted) ;; The called function might be an assignment in the ;; case where we are currently converting that function. @@ -923,7 +915,7 @@ ;;; tail-recursive local calls. ;;; -- If CALL is a non-tail call, or if both have returns, then ;;; we delete the callee's return, move its uses to the call's -;;; result continuation, and transfer control to the appropriate +;;; result lvar, and transfer control to the appropriate ;;; return point. ;;; -- If the callee has a return, but the caller doesn't, then we ;;; move the return to the caller. @@ -935,21 +927,29 @@ (let* ((return (lambda-return fun)) (call-fun (node-home-lambda call)) (call-return (lambda-return call-fun))) + (when (and call-return + (block-delete-p (node-block call-return))) + (delete-return call-return) + (unlink-node call-return) + (setq call-return nil)) (cond ((not return)) ((or next-block call-return) (unless (block-delete-p (node-block return)) - (move-return-uses fun call - (or next-block (node-block call-return))))) + (unless next-block + (ensure-block-start (node-prev call-return)) + (setq next-block (node-block call-return))) + (move-return-uses fun call next-block))) (t (aver (node-tail-p call)) (setf (lambda-return call-fun) return) - (setf (return-lambda return) call-fun)))) - (move-let-call-cont fun) + (setf (return-lambda return) call-fun) + (setf (lambda-return fun) nil)))) + (%delete-lvar-use call) ; LET call does not have value semantics (values)) ;;; Actually do LET conversion. We call subfunctions to do most of the ;;; work. We change the CALL's CONT to be the continuation heading the -;;; BIND block, and also do REOPTIMIZE-CONTINUATION on the args and +;;; BIND block, and also do REOPTIMIZE-LVAR on the args and ;;; CONT so that LET-specific IR1 optimizations get a chance. We blow ;;; away any entry for the function in *FREE-FUNS* so that nobody ;;; will create new references to it. @@ -966,8 +966,8 @@ (declare (type basic-combination call)) (dolist (arg (basic-combination-args call)) (when arg - (reoptimize-continuation arg))) - (reoptimize-continuation (node-cont call)) + (reoptimize-lvar arg))) + (reoptimize-lvar (node-lvar call)) (values)) ;;; Are there any declarations in force to say CLAMBDA shouldn't be @@ -976,15 +976,16 @@ ;; From the user's point of view, LET-converting something that ;; has a name is inlining it. (The user can't see what we're doing ;; with anonymous things, and suppressing inlining - ;; for such things can easily give Python acute indigestion, so + ;; for such things can easily give Python acute indigestion, so ;; we don't.) (when (leaf-has-source-name-p clambda) ;; ANSI requires that explicit NOTINLINE be respected. (or (eq (lambda-inlinep clambda) :notinline) - ;; If (> DEBUG SPEED) we can guess that inlining generally - ;; won't be appreciated, but if the user specifically requests - ;; inlining, that takes precedence over our general guess. - (and (policy clambda (> debug speed)) + ;; If (= LET-CONVERTION 0) we can guess that inlining + ;; generally won't be appreciated, but if the user + ;; specifically requests inlining, that takes precedence over + ;; our general guess. + (and (policy clambda (= let-convertion 0)) (not (eq (lambda-inlinep clambda) :inline)))))) ;;; We also don't convert calls to named functions which appear in the @@ -1024,21 +1025,24 @@ (let ((refs (leaf-refs clambda))) (when (and refs (null (rest refs)) - (member (functional-kind clambda) '(nil :assignment)) + (memq (functional-kind clambda) '(nil :assignment)) (not (functional-entry-fun clambda))) - (let* ((ref-cont (node-cont (first refs))) - (dest (continuation-dest ref-cont))) - (when (and dest - (basic-combination-p dest) - (eq (basic-combination-fun dest) ref-cont) + (binding* ((ref (first refs)) + (ref-lvar (node-lvar ref) :exit-if-null) + (dest (lvar-dest ref-lvar))) + (when (and (basic-combination-p dest) + (eq (basic-combination-fun dest) ref-lvar) (eq (basic-combination-kind dest) :local) (not (block-delete-p (node-block dest))) (cond ((ok-initial-convert-p clambda) t) (t - (reoptimize-continuation ref-cont) + (reoptimize-lvar ref-lvar) nil))) + (when (eq clambda (node-home-lambda dest)) + (delete-lambda clambda) + (return-from maybe-let-convert nil)) (unless (eq (functional-kind clambda) :assignment) - (let-convert clambda dest)) + (let-convert clambda dest)) (reoptimize-call dest) (setf (functional-kind clambda) (if (mv-combination-p dest) :mv-let :let)))) @@ -1066,30 +1070,28 @@ ;;; If a potentially TR local call really is TR, then convert it to ;;; jump directly to the called function. We also call ;;; MAYBE-CONVERT-TO-ASSIGNMENT. The first value is true if we -;;; tail-convert. The second is the value of M-C-T-A. We can switch -;;; the succesor (potentially deleting the RETURN node) unless: -;;; -- The call has already been converted. -;;; -- The call isn't TR (some implicit MV PROG1.) -;;; -- The call is in an XEP (thus we might decide to make it non-tail -;;; so that we can use known return inside the component.) -;;; -- There is a change in the cleanup between the call in the return, -;;; so we might need to introduce cleanup code. +;;; tail-convert. The second is the value of M-C-T-A. (defun maybe-convert-tail-local-call (call) (declare (type combination call)) - (let ((return (continuation-dest (node-cont call)))) + (let ((return (lvar-dest (node-lvar call)))) (aver (return-p return)) - (when (and (not (node-tail-p call)) + (when (and (not (node-tail-p call)) ; otherwise already converted + ;; this is a tail call (immediately-used-p (return-result return) call) - (not (eq (functional-kind (node-home-lambda call)) - :external)) (only-harmless-cleanups (node-block call) - (node-block return))) + (node-block return)) + ;; If the call is in an XEP, we might decide to make it + ;; non-tail so that we can use known return inside the + ;; component. + (not (eq (functional-kind (node-home-lambda call)) + :external))) (node-ends-block call) (let ((block (node-block call)) (fun (combination-lambda call))) (setf (node-tail-p call) t) (unlink-blocks block (first (block-succ block))) (link-blocks block (lambda-block fun)) + (delete-lvar-use call) (values t (maybe-convert-to-assignment fun)))))) ;;; This is called when we believe it might make sense to convert @@ -1117,28 +1119,27 @@ (declare (type clambda clambda)) (when (and (not (functional-kind clambda)) (not (functional-entry-fun clambda))) - (let ((non-tail nil) - (call-fun nil)) + (let ((outside-non-tail-call nil) + (outside-call nil)) (when (and (dolist (ref (leaf-refs clambda) t) - (let ((dest (continuation-dest (node-cont ref)))) + (let ((dest (lvar-dest (node-lvar ref)))) (when (or (not dest) (block-delete-p (node-block dest))) (return nil)) (let ((home (node-home-lambda ref))) (unless (eq home clambda) - (when call-fun + (when outside-call (return nil)) - (setq call-fun home)) + (setq outside-call dest)) (unless (node-tail-p dest) - (when (or non-tail (eq home clambda)) + (when (or outside-non-tail-call (eq home clambda)) (return nil)) - (setq non-tail dest))))) + (setq outside-non-tail-call dest))))) (ok-initial-convert-p clambda)) - (setf (functional-kind clambda) :assignment) - (let-convert clambda - (or non-tail - (continuation-dest - (node-cont (first (leaf-refs clambda)))))) - (when non-tail - (reoptimize-call non-tail)) - t)))) + (cond (outside-call (setf (functional-kind clambda) :assignment) + (let-convert clambda outside-call) + (when outside-non-tail-call + (reoptimize-call outside-non-tail-call)) + t) + (t (delete-lambda clambda) + nil))))))