Add instructions for doing very late binding
[bpt/guile.git] / module / system / il / compile.scm
CommitLineData
17e90c5e
KN
1;;; GHIL -> GLIL compiler
2
3;; Copyright (C) 2001 Free Software Foundation, Inc.
4
5;; This program is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation; either version 2, or (at your option)
8;; any later version.
9;;
10;; This program 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
13;; GNU General Public License for more details.
14;;
15;; You should have received a copy of the GNU General Public License
16;; along with this program; see the file COPYING. If not, write to
17;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18;; Boston, MA 02111-1307, USA.
19
20;;; Code:
21
22(define-module (system il compile)
17e90c5e 23 :use-syntax (system base syntax)
17e90c5e
KN
24 :use-module (system il glil)
25 :use-module (system il ghil)
26 :use-module (ice-9 common-list)
27 :export (compile))
28
29(define (compile x e . opts)
17e90c5e
KN
30 (if (memq :O opts) (set! x (optimize x)))
31 (codegen x))
32
33\f
34;;;
35;;; Stage 2: Optimization
36;;;
37
38(define (optimize x)
67169b29 39 (record-case x
61dc81d9 40 ((<ghil-set> env loc var val)
849cefac 41 (make-ghil-set env var (optimize val)))
3616e9e9 42
61dc81d9 43 ((<ghil-if> env loc test then else)
849cefac 44 (make-ghil-if (optimize test) (optimize then) (optimize else)))
3616e9e9 45
61dc81d9 46 ((<ghil-begin> env loc exps)
849cefac 47 (make-ghil-begin (map optimize exps)))
3616e9e9 48
61dc81d9 49 ((<ghil-bind> env loc vars vals body)
849cefac 50 (make-ghil-bind env vars (map optimize vals) (optimize body)))
3616e9e9 51
61dc81d9 52 ((<ghil-lambda> env loc vars rest body)
849cefac 53 (make-ghil-lambda env vars rest (optimize body)))
3616e9e9 54
a52b2d3d
LC
55;; FIXME: <ghil-inst> does not exist. -- Ludo'.
56; (($ <ghil-inst> inst args)
849cefac 57; (make-ghil-inst inst (map optimize args)))
3616e9e9 58
61dc81d9
AW
59 ((<ghil-call> env loc proc args)
60 (let ((parent-env env))
61 (record-case proc
62 ;; ((@lambda (VAR...) BODY...) ARG...) =>
63 ;; (@let ((VAR ARG) ...) BODY...)
64 ((<ghil-lambda> env loc vars rest body)
65 (cond
66 ((not rest)
67 (for-each (lambda (v)
68 (case (ghil-var-kind v)
69 ((argument) (set! (ghil-var-kind v) 'local)))
70 (set! (ghil-var-env v) parent-env)
71 (ghil-env-add! parent-env v))
72 (ghil-env-variables env)))
73 (else
74 (make-ghil-call parent-env (optimize proc) (map optimize args)))))
75 (else
76 (make-ghil-call parent-env (optimize proc) (map optimize args))))))
77
17e90c5e
KN
78 (else x)))
79
80\f
81;;;
82;;; Stage 3: Code generation
83;;;
84
849cefac
AW
85(define *ia-void* (make-glil-void))
86(define *ia-drop* (make-glil-call 'drop 0))
87(define *ia-return* (make-glil-call 'return 0))
17e90c5e
KN
88
89(define (make-label) (gensym ":L"))
90
91(define (make-glil-var op env var)
aa0a011b 92 (case (ghil-var-kind var)
17e90c5e 93 ((argument)
aa0a011b 94 (make-glil-argument op (ghil-var-index var)))
17e90c5e 95 ((local)
aa0a011b 96 (make-glil-local op (ghil-var-index var)))
17e90c5e
KN
97 ((external)
98 (do ((depth 0 (1+ depth))
aa0a011b
AW
99 (e env (ghil-env-parent e)))
100 ((eq? e (ghil-var-env var))
101 (make-glil-external op depth (ghil-var-index var)))))
17e90c5e 102 ((module)
6167de4f
AW
103 (let ((env (ghil-var-env var)))
104 (make-glil-module op (and env (ghil-mod-module (ghil-env-mod env)))
105 (ghil-var-name var))))
9cc649b8
AW
106 ((unresolved)
107 (make-glil-late-bound op (ghil-var-name var)))
17e90c5e
KN
108 (else (error "Unknown kind of variable:" var))))
109
110(define (codegen ghil)
111 (let ((stack '()))
112 (define (push-code! code)
113 (set! stack (cons code stack)))
aa0a011b
AW
114 (define (push-bindings! vars)
115 (if (not (null? vars))
116 (push-code!
117 (make-glil-bind
118 (map list
119 (map ghil-var-name vars)
120 (map ghil-var-kind vars)
121 (map ghil-var-index vars))))))
17e90c5e 122 (define (comp tree tail drop)
cb4cca12 123 (define (push-label! label)
849cefac 124 (push-code! (make-glil-label label)))
cb4cca12 125 (define (push-branch! inst label)
849cefac 126 (push-code! (make-glil-branch inst label)))
ac99cb0c 127 (define (push-call! loc inst args)
cb4cca12 128 (for-each comp-push args)
849cefac
AW
129 (push-code! (make-glil-call inst (length args)))
130 (push-code! (make-glil-source loc)))
17e90c5e
KN
131 ;; possible tail position
132 (define (comp-tail tree) (comp tree tail drop))
133 ;; push the result
134 (define (comp-push tree) (comp tree #f #f))
135 ;; drop the result
136 (define (comp-drop tree) (comp tree #f #t))
cb4cca12
KN
137 ;; drop the result if unnecessary
138 (define (maybe-drop)
139 (if drop (push-code! *ia-drop*)))
140 ;; return here if necessary
141 (define (maybe-return)
142 (if tail (push-code! *ia-return*)))
17e90c5e
KN
143 ;; return this code if necessary
144 (define (return-code! code)
145 (if (not drop) (push-code! code))
cb4cca12 146 (maybe-return))
17e90c5e 147 ;; return void if necessary
cb4cca12
KN
148 (define (return-void!)
149 (return-code! *ia-void*))
150 ;; return object if necessary
151 (define (return-object! obj)
10be7025 152 (return-code! (make-glil-const #:obj obj)))
17e90c5e
KN
153 ;;
154 ;; dispatch
67169b29
AW
155 (record-case tree
156 ((<ghil-void>)
17e90c5e
KN
157 (return-void!))
158
67169b29 159 ((<ghil-quote> env loc obj)
cb4cca12
KN
160 (return-object! obj))
161
67169b29 162 ((<ghil-quasiquote> env loc exp)
cb4cca12 163 (let loop ((x exp))
67169b29
AW
164 (cond
165 ((list? x)
166 (push-call! #f 'mark '())
167 (for-each loop x)
168 (push-call! #f 'list-mark '()))
169 ((pair? x)
170 (loop (car x))
171 (loop (cdr x))
172 (push-code! (make-glil-call 'cons 2)))
173 ((record? x)
174 (record-case x
175 ((<ghil-unquote> env loc exp)
176 (comp-push exp))
177 ((<ghil-unquote-splicing> env loc exp)
178 (comp-push exp)
179 (push-call! #f 'list-break '()))))
180 (else
10be7025 181 (push-code! (make-glil-const #:obj x)))))
cb4cca12
KN
182 (maybe-drop)
183 (maybe-return))
17e90c5e 184
67169b29 185 ((<ghil-ref> env loc var)
17e90c5e
KN
186 (return-code! (make-glil-var 'ref env var)))
187
67169b29 188 ((<ghil-set> env loc var val)
ac99cb0c
KN
189 (comp-push val)
190 (push-code! (make-glil-var 'set env var))
191 (return-void!))
192
67169b29 193 ((<ghil-define> env loc var val)
17e90c5e 194 (comp-push val)
cd9d95d7 195 (push-code! (make-glil-var 'define env var))
17e90c5e
KN
196 (return-void!))
197
67169b29 198 ((<ghil-if> env loc test then else)
17e90c5e
KN
199 ;; TEST
200 ;; (br-if-not L1)
201 ;; THEN
41f248a8 202 ;; (br L2)
17e90c5e
KN
203 ;; L1: ELSE
204 ;; L2:
205 (let ((L1 (make-label)) (L2 (make-label)))
206 (comp-push test)
cb4cca12 207 (push-branch! 'br-if-not L1)
17e90c5e 208 (comp-tail then)
cb4cca12
KN
209 (if (not tail) (push-branch! 'br L2))
210 (push-label! L1)
17e90c5e 211 (comp-tail else)
cb4cca12
KN
212 (if (not tail) (push-label! L2))))
213
67169b29 214 ((<ghil-and> env loc exps)
cb4cca12
KN
215 ;; EXP
216 ;; (br-if-not L1)
217 ;; ...
218 ;; TAIL
219 ;; (br L2)
220 ;; L1: (const #f)
221 ;; L2:
222 (let ((L1 (make-label)) (L2 (make-label)))
223 (if (null? exps)
224 (return-object! #t)
225 (do ((exps exps (cdr exps)))
226 ((null? (cdr exps))
227 (comp-tail (car exps))
228 (if (not tail) (push-branch! 'br L2))
229 (push-label! L1)
230 (return-object! #f)
231 (if (not tail) (push-label! L2))
232 (maybe-drop)
233 (maybe-return))
234 (comp-push (car exps))
235 (push-branch! 'br-if-not L1)))))
236
67169b29 237 ((<ghil-or> env loc exps)
cb4cca12
KN
238 ;; EXP
239 ;; (dup)
240 ;; (br-if L1)
241 ;; (drop)
242 ;; ...
243 ;; TAIL
244 ;; L1:
245 (let ((L1 (make-label)))
246 (if (null? exps)
247 (return-object! #f)
248 (do ((exps exps (cdr exps)))
249 ((null? (cdr exps))
250 (comp-tail (car exps))
251 (push-label! L1)
252 (maybe-drop)
253 (maybe-return))
254 (comp-push (car exps))
ac99cb0c 255 (push-call! #f 'dup '())
cb4cca12 256 (push-branch! 'br-if L1)
ac99cb0c 257 (push-call! #f 'drop '())))))
17e90c5e 258
67169b29 259 ((<ghil-begin> env loc exps)
17e90c5e
KN
260 ;; EXPS...
261 ;; TAIL
262 (if (null? exps)
263 (return-void!)
264 (do ((exps exps (cdr exps)))
265 ((null? (cdr exps))
266 (comp-tail (car exps)))
267 (comp-drop (car exps)))))
268
67169b29 269 ((<ghil-bind> env loc vars vals body)
17e90c5e
KN
270 ;; VALS...
271 ;; (set VARS)...
272 ;; BODY
273 (for-each comp-push vals)
aa0a011b 274 (push-bindings! vars)
a6df585a
KN
275 (for-each (lambda (var) (push-code! (make-glil-var 'set env var)))
276 (reverse vars))
ac99cb0c 277 (comp-tail body)
849cefac 278 (push-code! (make-glil-unbind)))
17e90c5e 279
67169b29 280 ((<ghil-lambda> env loc vars rest body)
17e90c5e
KN
281 (return-code! (codegen tree)))
282
f540e327 283 ((<ghil-inline> env loc inline args)
46cd9a34
KN
284 ;; ARGS...
285 ;; (INST NARGS)
f540e327 286 (push-call! loc inline args)
cb4cca12
KN
287 (maybe-drop)
288 (maybe-return))
46cd9a34 289
67169b29 290 ((<ghil-call> env loc proc args)
17e90c5e 291 ;; PROC
3616e9e9 292 ;; ARGS...
17e90c5e 293 ;; ([tail-]call NARGS)
17e90c5e 294 (comp-push proc)
ac99cb0c 295 (push-call! loc (if tail 'tail-call 'call) args)
cb4cca12 296 (maybe-drop))))
17e90c5e
KN
297 ;;
298 ;; main
67169b29 299 (record-case ghil
f540e327
AW
300 ((<ghil-lambda> env loc vars rest body)
301 (let* ((evars (ghil-env-variables env))
302 (locs (pick (lambda (v) (eq? (ghil-var-kind v) 'local)) evars))
303 (exts (pick (lambda (v) (eq? (ghil-var-kind v) 'external)) evars)))
17e90c5e 304 ;; initialize variable indexes
f540e327 305 (finalize-index! vars)
17e90c5e
KN
306 (finalize-index! locs)
307 (finalize-index! exts)
ac99cb0c 308 ;; meta bindings
f540e327 309 (push-bindings! vars)
17e90c5e 310 ;; export arguments
061f7fae 311 (do ((n 0 (1+ n))
f540e327 312 (l vars (cdr l)))
17e90c5e
KN
313 ((null? l))
314 (let ((v (car l)))
aa0a011b
AW
315 (case (ghil-var-kind v)
316 ((external)
317 (push-code! (make-glil-argument 'ref n))
318 (push-code! (make-glil-external 'set 0 (ghil-var-index v)))))))
17e90c5e
KN
319 ;; compile body
320 (comp body #t #f)
321 ;; create GLIL
f540e327 322 (let ((vars (make-glil-vars :nargs (length vars)
849cefac
AW
323 :nrest (if rest 1 0)
324 :nlocs (length locs)
325 :nexts (length exts))))
326 (make-glil-asm vars (reverse! stack))))))))
17e90c5e
KN
327
328(define (finalize-index! list)
329 (do ((n 0 (1+ n))
330 (l list (cdr l)))
331 ((null? l))
aa0a011b 332 (let ((v (car l))) (set! (ghil-var-index v) n))))