From d10fefe27031c0468424466c49aa80c21fb325a8 Mon Sep 17 00:00:00 2001
From: Peter Bex <peter.bex@xs4all.nl>
Date: Sun, 15 Dec 2013 16:04:27 +0100
Subject: [PATCH] Fix #1068 (partially!) by removing returnvar-passing from
CPS-conversion
---
compiler.scm | 53 +++++++++++++++++++++-------------------------
tests/compiler-tests.scm | 9 ++++++++
tests/syntax-tests.scm | 14 +++++++++++-
3 files changed, 46 insertions(+), 30 deletions(-)
diff --git a/compiler.scm b/compiler.scm
index 0398eef..f356eaf 100644
a
|
b
|
|
1688 | 1688 | |
1689 | 1689 | (define (perform-cps-conversion node) |
1690 | 1690 | |
1691 | | (define (cps-lambda id returnvar llist subs k) |
1692 | | (let ([t1 (or returnvar (gensym 'k))]) |
| 1691 | (define (cps-lambda id llist subs k) |
| 1692 | (let ([t1 (gensym 'k)]) |
1693 | 1693 | (k (make-node |
1694 | 1694 | '##core#lambda (list id #t (cons t1 llist) 0) |
1695 | | (list (walk (gensym-f-id) |
1696 | | (car subs) |
| 1695 | (list (walk (car subs) |
1697 | 1696 | (lambda (r) |
1698 | 1697 | (make-node '##core#call (list #t) (list (varnode t1) r)) ) ) ) ) ) ) ) |
1699 | 1698 | |
… |
… |
|
1701 | 1700 | (and (eq? (node-class node) '##core#variable) |
1702 | 1701 | (eq? (car (node-parameters node)) var))) |
1703 | 1702 | |
1704 | | (define (walk returnvar n k) |
| 1703 | (define (walk n k) |
1705 | 1704 | (let ((subs (node-subexpressions n)) |
1706 | 1705 | (params (node-parameters n)) |
1707 | 1706 | (class (node-class n)) ) |
1708 | 1707 | (case (node-class n) |
1709 | 1708 | ((##core#variable quote ##core#undefined ##core#primitive) (k n)) |
1710 | 1709 | ((if) (let* ((t1 (gensym 'k)) |
1711 | | (t2 (or returnvar (gensym 'r))) |
| 1710 | (t2 (gensym 'r)) |
1712 | 1711 | (k1 (lambda (r) (make-node '##core#call (list #t) (list (varnode t1) r)))) ) |
1713 | 1712 | (make-node |
1714 | 1713 | 'let |
1715 | 1714 | (list t1) |
1716 | 1715 | (list (make-node '##core#lambda (list (gensym-f-id) #f (list t2) 0) |
1717 | 1716 | (list (k (varnode t2))) ) |
1718 | | (walk #f (car subs) |
| 1717 | (walk (car subs) |
1719 | 1718 | (lambda (v) |
1720 | 1719 | (make-node 'if '() |
1721 | 1720 | (list v |
1722 | | (walk #f (cadr subs) k1) |
1723 | | (walk #f (caddr subs) k1) ) ) ) ) ) ) ) ) |
| 1721 | (walk (cadr subs) k1) |
| 1722 | (walk (caddr subs) k1) ) ) ) ) ) ) ) ) |
1724 | 1723 | ((let) |
1725 | 1724 | (let loop ((vars params) (vals subs)) |
1726 | 1725 | (if (null? vars) |
1727 | | (walk #f (car vals) k) |
1728 | | (walk (car vars) |
1729 | | (car vals) |
| 1726 | (walk (car vals) k) |
| 1727 | (walk (car vals) |
1730 | 1728 | (lambda (r) |
1731 | 1729 | (if (node-for-var? r (car vars)) ; Don't generate unneccessary lets |
1732 | 1730 | (loop (cdr vars) (cdr vals)) |
1733 | 1731 | (make-node 'let |
1734 | 1732 | (list (car vars)) |
1735 | 1733 | (list r (loop (cdr vars) (cdr vals))) )) ) ) ) ) ) |
1736 | | ((lambda ##core#lambda) (cps-lambda (gensym-f-id) returnvar (first params) subs k)) |
| 1734 | ((lambda ##core#lambda) (cps-lambda (gensym-f-id) (first params) subs k)) |
1737 | 1735 | ((set!) (let ((t1 (gensym 't))) |
1738 | | (walk #f |
1739 | | (car subs) |
| 1736 | (walk (car subs) |
1740 | 1737 | (lambda (r) |
1741 | 1738 | (make-node 'let (list t1) |
1742 | 1739 | (list (make-node 'set! (list (first params)) (list r)) |
… |
… |
|
1748 | 1745 | (cons (apply make-foreign-callback-stub id params) foreign-callback-stubs) ) |
1749 | 1746 | ;; mark to avoid leaf-routine optimization |
1750 | 1747 | (mark-variable id '##compiler#callback-lambda) |
1751 | | ;; maybe pass returnvar here? |
1752 | | (cps-lambda id #f (first (node-parameters lam)) (node-subexpressions lam) k) ) ) |
| 1748 | (cps-lambda id (first (node-parameters lam)) (node-subexpressions lam) k) ) ) |
1753 | 1749 | ((##core#inline ##core#inline_allocate ##core#inline_ref ##core#inline_update ##core#inline_loc_ref |
1754 | 1750 | ##core#inline_loc_update) |
1755 | 1751 | (walk-inline-call class params subs k) ) |
1756 | | ((##core#call) (walk-call returnvar (car subs) (cdr subs) params k)) |
1757 | | ((##core#callunit) (walk-call-unit returnvar (first params) k)) |
| 1752 | ((##core#call) (walk-call (car subs) (cdr subs) params k)) |
| 1753 | ((##core#callunit) (walk-call-unit (first params) k)) |
1758 | 1754 | ((##core#the ##core#the/result) |
1759 | 1755 | ;; remove "the" nodes, as they are not used after scrutiny |
1760 | | (walk returnvar (car subs) k)) |
| 1756 | (walk (car subs) k)) |
1761 | 1757 | ((##core#typecase) |
1762 | 1758 | ;; same here, the last clause is chosen, exp is dropped |
1763 | | (walk returnvar (last subs) k)) |
| 1759 | (walk (last subs) k)) |
1764 | 1760 | (else (bomb "bad node (cps)")) ) ) ) |
1765 | 1761 | |
1766 | | (define (walk-call returnvar fn args params k) |
| 1762 | (define (walk-call fn args params k) |
1767 | 1763 | (let ((t0 (gensym 'k)) |
1768 | | (t3 (or returnvar (gensym 'r))) ) |
| 1764 | (t3 (gensym 'r)) ) |
1769 | 1765 | (make-node |
1770 | 1766 | 'let (list t0) |
1771 | 1767 | (list (make-node '##core#lambda (list (gensym-f-id) #f (list t3) 0) |
… |
… |
|
1773 | 1769 | (walk-arguments |
1774 | 1770 | args |
1775 | 1771 | (lambda (vars) |
1776 | | (walk #f fn |
| 1772 | (walk fn |
1777 | 1773 | (lambda (r) |
1778 | 1774 | (make-node '##core#call params (cons* r (varnode t0) vars) ) ) ) ) ) ) ) ) ) |
1779 | 1775 | |
1780 | | (define (walk-call-unit returnvar unitname k) |
| 1776 | (define (walk-call-unit unitname k) |
1781 | 1777 | (let ((t0 (gensym 'k)) |
1782 | | (t3 (or returnvar (gensym 'r))) ) |
| 1778 | (t3 (gensym 'r)) ) |
1783 | 1779 | (make-node |
1784 | 1780 | 'let (list t0) |
1785 | 1781 | (list (make-node '##core#lambda (list (gensym-f-id) #f (list t3) 0) |
… |
… |
|
1800 | 1796 | (loop (cdr args) (cons (car args) vars)) ) |
1801 | 1797 | (else |
1802 | 1798 | (let ((t1 (gensym 'a))) |
1803 | | (walk t1 |
1804 | | (car args) |
| 1799 | (walk (car args) |
1805 | 1800 | (lambda (r) |
1806 | 1801 | (if (node-for-var? r t1) ; Don't generate unneccessary lets |
1807 | 1802 | (loop (cdr args) (cons (varnode t1) vars) ) |
… |
… |
|
1818 | 1813 | ##core#inline_loc_ref ##core#inline_loc_update)) |
1819 | 1814 | (every atomic? (node-subexpressions n)) ) ) ) ) |
1820 | 1815 | |
1821 | | (walk #f node values) ) |
| 1816 | (walk node values) ) |
1822 | 1817 | |
1823 | 1818 | |
1824 | 1819 | ;;; Foreign callback stub type: |
diff --git a/tests/compiler-tests.scm b/tests/compiler-tests.scm
index 45b6bfd..444aa50 100644
a
|
b
|
|
217 | 217 | |
218 | 218 | (gp-test) |
219 | 219 | |
| 220 | ;; Optimizer would "lift" inner-bar out of its let and replace |
| 221 | ;; outer-bar with it, even though it wasn't visible yet. Caused by |
| 222 | ;; broken cps-conversion (underlying problem for #1068). |
| 223 | (let ((outer-bar (##core#undefined))) |
| 224 | (let ((inner-bar (let ((tmp (lambda (x) (if x '1 (outer-bar '#t))))) |
| 225 | tmp))) |
| 226 | (set! outer-bar inner-bar) |
| 227 | (outer-bar #f))) |
| 228 | |
220 | 229 | ;; Test that encode-literal/decode-literal use the proper functions |
221 | 230 | ;; to decode number literals. |
222 | 231 | (assert (equal? '(+inf.0 -inf.0) (list (fp/ 1.0 0.0) (fp/ -1.0 0.0)))) |
diff --git a/tests/syntax-tests.scm b/tests/syntax-tests.scm
index a5f4323..89481cd 100644
a
|
b
|
take |
1113 | 1113 | (bar foo)) |
1114 | 1114 | bar)) |
1115 | 1115 | |
| 1116 | ;; Obscure letrec issue #1068 |
| 1117 | (t 1 (letrec ((foo (lambda () 1)) |
| 1118 | (bar (let ((tmp (lambda (x) (if x (foo) (bar #t))))) |
| 1119 | tmp))) |
| 1120 | (bar #f))) |
| 1121 | |
| 1122 | ;; Just to verify (this has always worked) |
| 1123 | (t 1 (letrec* ((foo (lambda () 1)) |
| 1124 | (bar (let ((tmp (lambda (x) (if x (foo) (bar #t))))) |
| 1125 | tmp))) |
| 1126 | (bar #f))) |
| 1127 | |
1116 | 1128 | (t 1 (letrec* ((foo 1) |
1117 | 1129 | (bar foo)) |
1118 | | bar)) |
| 1130 | bar)) |