add <primcall> to tree-il
[bpt/guile.git] / module / language / tree-il / inline.scm
CommitLineData
dab0f9d5
AW
1;;; a simple inliner
2
a75ea658 3;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
dab0f9d5 4
c21c89b1
AW
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 3 of the License, or (at your option) any later version.
9;;;;
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;;; Lesser General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
dab0f9d5
AW
18
19(define-module (language tree-il inline)
8a4ca0ea 20 #:use-module (system base pmatch)
dab0f9d5
AW
21 #:use-module (system base syntax)
22 #:use-module (language tree-il)
23 #:export (inline!))
24
25;; Possible optimizations:
26;; * constant folding, propagation
27;; * procedure inlining
28;; * always when single call site
29;; * always for "trivial" procs
30;; * otherwise who knows
31;; * dead code elimination
32;; * degenerate case optimizations
33;; * "fixing letrec"
34
0e4b7818
AW
35(define (boolean-value x)
36 (let ((src (tree-il-src x)))
37 (record-case x
38 ((<void>)
39 (make-const src #t))
40
41 ((<conditional> test consequent alternate)
42 (record-case (boolean-value test)
43 ((<const> exp)
44 (case exp
45 ((#t) (boolean-value consequent))
46 ((#f) (boolean-value alternate))
47 (else x)))
48 (else x)))
49
a881a4ae
AW
50 ((<primcall> src name args)
51 (pmatch (cons name args)
52 ((,member ,k ,l) (guard (and (memq member '(memq memv))
53 (const? k)
54 (list? (const-exp l))))
55 (cond
56 ((null? (const-exp l))
57 (make-const #f #f))
58 ((const? k)
59 (make-const #f (->bool ((case member
60 ((memq) memq)
61 ((memv) memv)
62 (else (error "what" member)))
63 (const-exp k) (const-exp l)))))
64 (else
65 (let lp ((elts (const-exp l)))
66 (let ((test (make-primcall
67 #f
68 (case member
69 ((memq) 'eq?)
70 ((memv) 'eqv?)
71 (else (error "what" member)))
72 (list k (make-const #f (car elts))))))
73 (if (null? (cdr elts))
74 test
75 (make-conditional
76 src
77 test
78 (make-const #f #t)
79 (lp (cdr elts)))))))))
a75ea658
AW
80 (else x)))
81
0e4b7818
AW
82 ((<lambda> meta body)
83 (make-const src #t))
84
85 ((<const> exp)
86 (make-const src (not (not exp))))
87
88 (else
89 x))))
90
dab0f9d5
AW
91;; This is a completely brain-dead optimization pass whose sole claim to
92;; fame is ((lambda () x)) => x.
93(define (inline! x)
8a4ca0ea
AW
94 (define (inline1 x)
95 (record-case x
7081d4f9 96 ((<call> src proc args)
8a4ca0ea
AW
97 (record-case proc
98 ;; ((lambda (y ...) x) z ...) => (let ((y z) ...) x)
99 ((<lambda> body)
100 (let lp ((lcase body))
101 (and lcase
102 (record-case lcase
93f63467
AW
103 ((<lambda-case> req opt rest kw inits gensyms body alternate)
104 (if (and (= (length gensyms) (length req) (length args)))
105 (let ((x (make-let src req gensyms args body)))
8a4ca0ea 106 (or (inline1 x) x))
3a88cb3b 107 (lp alternate)))))))
bca488f1 108
bca488f1 109 (else #f)))
80af1168 110
a881a4ae
AW
111 ((<primcall> src name args)
112 (pmatch (cons name args)
113 ;; (call-with-values (lambda () foo) (lambda (a b . c) bar))
114 ;; => (let-values (((a b . c) foo)) bar)
115 ;;
116 ;; Note that this is a singly-binding form of let-values. Also
117 ;; note that Scheme's let-values expands into call-with-values,
118 ;; then here we reduce it to tree-il's let-values.
119 ((@call-with-values ,producer ,consumer)
120 (guard (lambda? consumer)
121 (lambda-case? (lambda-body consumer))
122 (not (lambda-case-opt (lambda-body consumer)))
123 (not (lambda-case-kw (lambda-body consumer)))
124 (not (lambda-case-alternate (lambda-body consumer))))
125 (make-let-values
126 src
127 (let ((x (make-call src producer '())))
128 (or (inline1 x) x))
129 (lambda-body consumer)))
130 (else #f)))
131
0e4b7818
AW
132 ((<conditional> test consequent alternate)
133 (let ((btest (boolean-value test)))
134 (or (record-case btest
135 ((<const> exp)
136 (case exp
137 ((#t) consequent)
138 ((#f) alternate)
139 (else #f)))
140 (else #f))
141 (if (eq? test btest)
142 x
143 (make-conditional (conditional-src x)
144 btest consequent alternate)))))
145
93f63467
AW
146 ((<let> gensyms body)
147 (if (null? gensyms) body x))
80af1168 148
93f63467
AW
149 ((<letrec> gensyms body)
150 (if (null? gensyms) body x))
80af1168 151
93f63467
AW
152 ((<fix> gensyms body)
153 (if (null? gensyms) body x))
80af1168 154
93f63467
AW
155 ((<lambda-case> req opt rest kw gensyms body alternate)
156 (define (args-compatible? args gensyms)
157 (let lp ((args args) (gensyms gensyms))
ac644098 158 (cond
93f63467
AW
159 ((null? args) (null? gensyms))
160 ((null? gensyms) #f)
ac644098 161 ((and (lexical-ref? (car args))
93f63467
AW
162 (eq? (lexical-ref-gensym (car args)) (car gensyms)))
163 (lp (cdr args) (cdr gensyms)))
ac644098 164 (else #f))))
ea6b18e8 165
98dcf051 166 (and (not opt) (not kw) rest (not alternate)
ac644098 167 (record-case body
a881a4ae 168 ((<primcall> name args)
ac644098 169 ;; (lambda args (apply (lambda ...) args)) => (lambda ...)
a881a4ae 170 (and (eq? name '@apply)
ac644098
AW
171 (pair? args)
172 (lambda? (car args))
93f63467 173 (args-compatible? (cdr args) gensyms)
ac644098
AW
174 (lambda-body (car args))))
175 (else #f))))
176
177 ;; Actually the opposite of inlining -- if the prompt cannot be proven to
7081d4f9 178 ;; be escape-only, ensure that its body is the call of a thunk.
ac644098
AW
179 ((<prompt> src tag body handler)
180 (define (escape-only? handler)
181 (and (pair? (lambda-case-req handler))
93f63467 182 (let ((cont (car (lambda-case-gensyms handler))))
ac644098
AW
183 (tree-il-fold (lambda (leaf escape-only?)
184 (and escape-only?
185 (not
186 (and (lexical-ref? leaf)
187 (eq? (lexical-ref-gensym leaf) cont)))))
188 (lambda (down escape-only?) escape-only?)
189 (lambda (up escape-only?) escape-only?)
190 #t
191 (lambda-case-body handler)))))
192 (define (make-thunk body)
193 (make-lambda #f '() (make-lambda-case #f '() #f #f #f '() '() body #f)))
194
7081d4f9
AW
195 (if (or (and (call? body)
196 (lambda? (call-proc body))
197 (null? (call-args body)))
ac644098
AW
198 (escape-only? handler))
199 x
200 (make-prompt src tag
7081d4f9 201 (make-call #f (make-thunk body) '())
ac644098 202 handler)))
ea6b18e8 203
8a4ca0ea
AW
204 (else #f)))
205 (post-order! inline1 x))