Comment 1 for bug 309099

Revision history for this message
Roman Marynchak (roman-marynchak) wrote :

After some investigation it seems to me that the problem is connected with the wrong cleanup code insertion during the IR1 phase. Consider this part of the code flow:

IR1 block 5 start c52
start stack:
 52> 56: SB-C::%POP-VALUES {GLOBAL-FUNCTION}
 57> 58: '#<SB-C::LVAR 24 {B2FF8F9}>
 59> known combination v56 v58
end stack:
successors c60

Here %POP-VALUES works with the LVAR which is intended to store the return value (and holds a part of it already). The wrong insertion occurs in stack.lisp. As a quick and _very dirty_ workaround, remove the cleanup insertions in discard-unused-values, before the (when (cleanup-code) at the function end:

(defun discard-unused-values (block1 block2)
  (declare (type cblock block1 block2))
  (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))))

 ;;check our assumptions about the wrong cleanup code <-----------------------------------------------
 #+nil
 (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))))

  (values))

After SBCL is rebuild with that change, (buu 1) returns the expected value (:A :B :C).

I understand that this is not a proper fix, and I will try find the cause of the wrong insertion soon.

Regards,
Roman