- (let* ((block1-stack (ir2-block-end-stack (block-info block1)))
- (block2-stack (ir2-block-start-stack (block-info block2)))
- (last-popped (elt block1-stack
- (- (length block1-stack)
- (length block2-stack)
- 1))))
- (aver (tailp block2-stack block1-stack))
-
- (let* ((block (insert-cleanup-code block1 block2
- (block-start-node block2)
- `(%pop-values ',last-popped)))
- (2block (make-ir2-block block)))
- (setf (block-info block) 2block)
- (add-to-emit-order 2block (block-info block1))
- (ltn-analyze-belated-block block)))
+ (collect ((cleanup-code))
+ (labels ((find-popped (before after)
+ ;; Returns (VALUES popped last-popped rest), where
+ ;; BEFORE = (APPEND popped rest) and
+ ;; (EQ (FIRST rest) (FIRST after))
+ (if (null after)
+ (values before (first (last before)) nil)
+ (loop with first-preserved = (car after)
+ for last-popped = nil then maybe-popped
+ for rest on before
+ for maybe-popped = (car rest)
+ while (neq maybe-popped first-preserved)
+ collect maybe-popped into popped
+ finally (return (values popped last-popped rest)))))
+ (discard (before-stack after-stack)
+ (cond
+ ((eq (car before-stack) (car after-stack))
+ (binding* ((moved-count (mismatch before-stack after-stack)
+ :exit-if-null)
+ ((moved qmoved)
+ (loop for moved-lvar in before-stack
+ repeat moved-count
+ collect moved-lvar into moved
+ collect `',moved-lvar into qmoved
+ finally (return (values moved qmoved))))
+ (q-last-moved (car (last qmoved)))
+ ((nil last-nipped rest)
+ (find-popped (nthcdr moved-count before-stack)
+ (nthcdr moved-count after-stack))))
+ (cleanup-code
+ `(%nip-values ',last-nipped ,q-last-moved
+ ,@qmoved))
+ (discard (nconc moved rest) after-stack)))
+ (t
+ (multiple-value-bind (popped last-popped rest)
+ (find-popped before-stack after-stack)
+ (declare (ignore popped))
+ (cleanup-code `(%pop-values ',last-popped))
+ (discard rest after-stack))))))
+ (discard (ir2-block-end-stack (block-info block1))
+ (ir2-block-start-stack (block-info block2))))
+ (when (cleanup-code)
+ (let* ((block (insert-cleanup-code block1 block2
+ (block-start-node block2)
+ `(progn ,@(cleanup-code))))
+ (2block (make-ir2-block block)))
+ (setf (block-info block) 2block)
+ (add-to-emit-order 2block (block-info block1))
+ (ltn-analyze-belated-block block))))