add `compile-time-environment'
[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)
1a1a10d3
AW
23 #:use-syntax (system base syntax)
24 #:use-module (system il glil)
25 #:use-module (system il ghil)
26 #:use-module (ice-9 common-list)
27 #:export (compile))
17e90c5e
KN
28
29(define (compile x e . opts)
1a1a10d3 30 (if (memq #:O opts) (set! x (optimize x)))
17e90c5e
KN
31 (codegen x))
32
33\f
34;;;
35;;; Stage 2: Optimization
36;;;
37
d51406fe
AW
38(define (lift-variables! env)
39 (let ((parent-env (ghil-env-parent env)))
40 (for-each (lambda (v)
41 (case (ghil-var-kind v)
42 ((argument) (set! (ghil-var-kind v) 'local)))
43 (set! (ghil-var-env v) parent-env)
44 (ghil-env-add! parent-env v))
45 (ghil-env-variables env))))
46
17e90c5e 47(define (optimize x)
67169b29 48 (record-case x
61dc81d9 49 ((<ghil-set> env loc var val)
849cefac 50 (make-ghil-set env var (optimize val)))
3616e9e9 51
d51406fe
AW
52 ((<ghil-define> env loc var val)
53 (make-ghil-define env var (optimize val)))
54
61dc81d9 55 ((<ghil-if> env loc test then else)
22bcbe8c 56 (make-ghil-if env loc (optimize test) (optimize then) (optimize else)))
3616e9e9 57
d51406fe
AW
58 ((<ghil-and> env loc exps)
59 (make-ghil-and env loc (map optimize exps)))
60
61 ((<ghil-or> env loc exps)
62 (make-ghil-or env loc (map optimize exps)))
63
61dc81d9 64 ((<ghil-begin> env loc exps)
22bcbe8c 65 (make-ghil-begin env loc (map optimize exps)))
3616e9e9 66
61dc81d9 67 ((<ghil-bind> env loc vars vals body)
22bcbe8c 68 (make-ghil-bind env loc vars (map optimize vals) (optimize body)))
3616e9e9 69
fbde2b91
AW
70 ((<ghil-lambda> env loc vars rest meta body)
71 (make-ghil-lambda env loc vars rest meta (optimize body)))
3616e9e9 72
22bcbe8c
AW
73 ((<ghil-inline> env loc instruction args)
74 (make-ghil-inline env loc instruction (map optimize args)))
3616e9e9 75
61dc81d9
AW
76 ((<ghil-call> env loc proc args)
77 (let ((parent-env env))
78 (record-case proc
79 ;; ((@lambda (VAR...) BODY...) ARG...) =>
80 ;; (@let ((VAR ARG) ...) BODY...)
fbde2b91 81 ((<ghil-lambda> env loc vars rest meta body)
61dc81d9
AW
82 (cond
83 ((not rest)
d51406fe
AW
84 (lift-variables! env)
85 (make-ghil-bind parent-env loc (map optimize args)))
61dc81d9 86 (else
22bcbe8c 87 (make-ghil-call parent-env loc (optimize proc) (map optimize args)))))
61dc81d9 88 (else
22bcbe8c 89 (make-ghil-call parent-env loc (optimize proc) (map optimize args))))))
61dc81d9 90
d51406fe
AW
91 ((<ghil-mv-call> env loc producer consumer)
92 (record-case consumer
93 ;; (mv-call PRODUCER (lambda ARGS BODY...)) =>
94 ;; (mv-let PRODUCER ARGS BODY...)
95 ((<ghil-lambda> env loc vars rest meta body)
96 (lift-variables! env)
97 (make-ghil-mv-bind producer vars rest body))
98 (else
99 (make-ghil-mv-call env loc (optimize producer) (optimize consumer)))))
100
17e90c5e
KN
101 (else x)))
102
103\f
104;;;
105;;; Stage 3: Code generation
106;;;
107
849cefac
AW
108(define *ia-void* (make-glil-void))
109(define *ia-drop* (make-glil-call 'drop 0))
110(define *ia-return* (make-glil-call 'return 0))
17e90c5e
KN
111
112(define (make-label) (gensym ":L"))
113
114(define (make-glil-var op env var)
aa0a011b 115 (case (ghil-var-kind var)
17e90c5e 116 ((argument)
aa0a011b 117 (make-glil-argument op (ghil-var-index var)))
17e90c5e 118 ((local)
aa0a011b 119 (make-glil-local op (ghil-var-index var)))
17e90c5e
KN
120 ((external)
121 (do ((depth 0 (1+ depth))
aa0a011b
AW
122 (e env (ghil-env-parent e)))
123 ((eq? e (ghil-var-env var))
124 (make-glil-external op depth (ghil-var-index var)))))
a1122f8c
AW
125 ((toplevel)
126 (make-glil-toplevel op (ghil-var-name var)))
fd358575
AW
127 ((public private)
128 (make-glil-module op (ghil-var-env var) (ghil-var-name var)
129 (eq? (ghil-var-kind var) 'public)))
17e90c5e
KN
130 (else (error "Unknown kind of variable:" var))))
131
1b79210a
AW
132(define (constant? x)
133 (cond ((or (number? x) (string? x) (symbol? x) (keyword? x) (boolean? x)) #t)
134 ((pair? x) (and (constant? (car x))
135 (constant? (cdr x))))
136 ((vector? x) (let lp ((i (vector-length x)))
137 (or (zero? i)
138 (and (constant? (vector-ref x (1- i)))
139 (lp (1- i))))))))
140
17e90c5e
KN
141(define (codegen ghil)
142 (let ((stack '()))
96969dc1 143 (define (push-code! loc code)
d0168f3d
AW
144 (set! stack (cons code stack))
145 (if loc (set! stack (cons (make-glil-source loc) stack))))
d51406fe
AW
146 (define (var->binding var)
147 (list (ghil-var-name var) (ghil-var-kind var) (ghil-var-index var)))
96969dc1 148 (define (push-bindings! loc vars)
aa0a011b 149 (if (not (null? vars))
d51406fe 150 (push-code! loc (make-glil-bind (map var->binding vars)))))
17e90c5e 151 (define (comp tree tail drop)
cb4cca12 152 (define (push-label! label)
96969dc1
AW
153 (push-code! #f (make-glil-label label)))
154 (define (push-branch! loc inst label)
155 (push-code! loc (make-glil-branch inst label)))
ac99cb0c 156 (define (push-call! loc inst args)
cb4cca12 157 (for-each comp-push args)
96969dc1 158 (push-code! loc (make-glil-call inst (length args))))
17e90c5e
KN
159 ;; possible tail position
160 (define (comp-tail tree) (comp tree tail drop))
161 ;; push the result
162 (define (comp-push tree) (comp tree #f #f))
163 ;; drop the result
164 (define (comp-drop tree) (comp tree #f #t))
cb4cca12
KN
165 ;; drop the result if unnecessary
166 (define (maybe-drop)
96969dc1 167 (if drop (push-code! #f *ia-drop*)))
cb4cca12
KN
168 ;; return here if necessary
169 (define (maybe-return)
96969dc1 170 (if tail (push-code! #f *ia-return*)))
17e90c5e 171 ;; return this code if necessary
96969dc1
AW
172 (define (return-code! loc code)
173 (if (not drop) (push-code! loc code))
cb4cca12 174 (maybe-return))
17e90c5e 175 ;; return void if necessary
cb4cca12 176 (define (return-void!)
96969dc1 177 (return-code! #f *ia-void*))
cb4cca12 178 ;; return object if necessary
96969dc1
AW
179 (define (return-object! loc obj)
180 (return-code! loc (make-glil-const #:obj obj)))
17e90c5e
KN
181 ;;
182 ;; dispatch
67169b29
AW
183 (record-case tree
184 ((<ghil-void>)
17e90c5e
KN
185 (return-void!))
186
67169b29 187 ((<ghil-quote> env loc obj)
96969dc1 188 (return-object! loc obj))
cb4cca12 189
67169b29 190 ((<ghil-quasiquote> env loc exp)
2bd859c8 191 (let loop ((x exp) (in-car? #f))
67169b29
AW
192 (cond
193 ((list? x)
194 (push-call! #f 'mark '())
2bd859c8 195 (for-each (lambda (x) (loop x #t)) x)
67169b29
AW
196 (push-call! #f 'list-mark '()))
197 ((pair? x)
2bd859c8
AW
198 (push-call! #f 'mark '())
199 (loop (car x) #t)
200 (loop (cdr x) #f)
201 (push-call! #f 'cons-mark '()))
67169b29
AW
202 ((record? x)
203 (record-case x
204 ((<ghil-unquote> env loc exp)
205 (comp-push exp))
206 ((<ghil-unquote-splicing> env loc exp)
2bd859c8
AW
207 (if (not in-car?)
208 (error "unquote-splicing in the cdr of a pair" exp))
67169b29
AW
209 (comp-push exp)
210 (push-call! #f 'list-break '()))))
1b79210a
AW
211 ((constant? x)
212 (push-code! #f (make-glil-const #:obj x)))
67169b29 213 (else
1b79210a 214 (error "element of quasiquote can't be compiled" x))))
cb4cca12
KN
215 (maybe-drop)
216 (maybe-return))
17e90c5e 217
67169b29 218 ((<ghil-ref> env loc var)
96969dc1 219 (return-code! loc (make-glil-var 'ref env var)))
17e90c5e 220
67169b29 221 ((<ghil-set> env loc var val)
ac99cb0c 222 (comp-push val)
96969dc1 223 (push-code! loc (make-glil-var 'set env var))
ac99cb0c
KN
224 (return-void!))
225
67169b29 226 ((<ghil-define> env loc var val)
17e90c5e 227 (comp-push val)
96969dc1 228 (push-code! loc (make-glil-var 'define env var))
17e90c5e
KN
229 (return-void!))
230
67169b29 231 ((<ghil-if> env loc test then else)
17e90c5e
KN
232 ;; TEST
233 ;; (br-if-not L1)
234 ;; THEN
41f248a8 235 ;; (br L2)
17e90c5e
KN
236 ;; L1: ELSE
237 ;; L2:
238 (let ((L1 (make-label)) (L2 (make-label)))
239 (comp-push test)
96969dc1 240 (push-branch! loc 'br-if-not L1)
17e90c5e 241 (comp-tail then)
96969dc1 242 (if (not tail) (push-branch! #f 'br L2))
cb4cca12 243 (push-label! L1)
17e90c5e 244 (comp-tail else)
cb4cca12
KN
245 (if (not tail) (push-label! L2))))
246
67169b29 247 ((<ghil-and> env loc exps)
cb4cca12
KN
248 ;; EXP
249 ;; (br-if-not L1)
250 ;; ...
251 ;; TAIL
252 ;; (br L2)
253 ;; L1: (const #f)
254 ;; L2:
7e4760e4
AW
255 (cond ((null? exps) (return-object! loc #t))
256 ((null? (cdr exps)) (comp-tail (car exps)))
257 (else
258 (let ((L1 (make-label)) (L2 (make-label)))
259 (let lp ((exps exps))
260 (cond ((null? (cdr exps))
261 (comp-tail (car exps))
262 (push-branch! #f 'br L2)
263 (push-label! L1)
264 (return-object! #f #f)
265 (push-label! L2)
266 (maybe-return))
267 (else
268 (comp-push (car exps))
269 (push-branch! #f 'br-if-not L1)
270 (lp (cdr exps)))))))))
cb4cca12 271
67169b29 272 ((<ghil-or> env loc exps)
cb4cca12
KN
273 ;; EXP
274 ;; (dup)
275 ;; (br-if L1)
276 ;; (drop)
277 ;; ...
278 ;; TAIL
279 ;; L1:
7e4760e4
AW
280 (cond ((null? exps) (return-object! loc #f))
281 ((null? (cdr exps)) (comp-tail (car exps)))
282 (else
283 (let ((L1 (make-label)))
284 (let lp ((exps exps))
285 (cond ((null? (cdr exps))
286 (comp-tail (car exps))
287 (push-label! L1)
288 (maybe-return))
289 (else
290 (comp-push (car exps))
535ed4d0
AW
291 (if (not drop)
292 (push-call! #f 'dup '()))
7e4760e4 293 (push-branch! #f 'br-if L1)
535ed4d0
AW
294 (if (not drop)
295 (push-call! #f 'drop '()))
7e4760e4 296 (lp (cdr exps)))))))))
17e90c5e 297
67169b29 298 ((<ghil-begin> env loc exps)
17e90c5e
KN
299 ;; EXPS...
300 ;; TAIL
301 (if (null? exps)
302 (return-void!)
303 (do ((exps exps (cdr exps)))
304 ((null? (cdr exps))
305 (comp-tail (car exps)))
306 (comp-drop (car exps)))))
307
67169b29 308 ((<ghil-bind> env loc vars vals body)
17e90c5e
KN
309 ;; VALS...
310 ;; (set VARS)...
311 ;; BODY
312 (for-each comp-push vals)
96969dc1
AW
313 (push-bindings! loc vars)
314 (for-each (lambda (var) (push-code! #f (make-glil-var 'set env var)))
a6df585a 315 (reverse vars))
ac99cb0c 316 (comp-tail body)
96969dc1 317 (push-code! #f (make-glil-unbind)))
17e90c5e 318
d51406fe
AW
319 ((<ghil-mv-bind> env loc producer vars rest body)
320 ;; VALS...
321 ;; (set VARS)...
322 ;; BODY
323 (let ((MV (make-label)))
324 (comp-push producer)
325 (push-code! loc (make-glil-mv-call 0 MV))
326 (push-code! #f (make-glil-const #:obj 1))
327 (push-label! MV)
328 (push-code! #f (make-glil-mv-bind (map var->binding vars) rest))
329 (for-each (lambda (var) (push-code! #f (make-glil-var 'set env var)))
330 (reverse vars)))
331 (comp-tail body)
332 (push-code! #f (make-glil-unbind)))
333
fbde2b91 334 ((<ghil-lambda> env loc vars rest meta body)
96969dc1 335 (return-code! loc (codegen tree)))
17e90c5e 336
f540e327 337 ((<ghil-inline> env loc inline args)
46cd9a34
KN
338 ;; ARGS...
339 ;; (INST NARGS)
76282387
AW
340 (let ((tail-table '((call . goto/args)
341 (apply . goto/apply)
342 (call/cc . goto/cc))))
343 (cond ((and tail (assq-ref tail-table inline))
344 => (lambda (tail-inst)
345 (push-call! loc tail-inst args)))
346 (else
347 (push-call! loc inline args)
348 (maybe-drop)
349 (maybe-return)))))
46cd9a34 350
a222b0fa
AW
351 ((<ghil-values> env loc values)
352 (cond (tail ;; (lambda () (values 1 2))
353 (push-call! loc 'return/values values))
354 (drop ;; (lambda () (values 1 2) 3)
355 (for-each comp-drop values))
356 (else ;; (lambda () (list (values 10 12) 1))
357 (push-code! #f (make-glil-const #:obj 'values))
358 (push-code! #f (make-glil-call #:inst 'link-now #:nargs 1))
359 (push-code! #f (make-glil-call #:inst 'variable-ref #:nargs 0))
360 (push-call! loc 'call values))))
361
ef24c01b
AW
362 ((<ghil-values*> env loc values)
363 (cond (tail ;; (lambda () (apply values '(1 2)))
364 (push-call! loc 'return/values* values))
365 (drop ;; (lambda () (apply values '(1 2)) 3)
366 (for-each comp-drop values))
367 (else ;; (lambda () (list (apply values '(10 12)) 1))
368 (push-code! #f (make-glil-const #:obj 'values))
369 (push-code! #f (make-glil-call #:inst 'link-now #:nargs 1))
370 (push-code! #f (make-glil-call #:inst 'variable-ref #:nargs 0))
371 (push-call! loc 'apply values))))
372
67169b29 373 ((<ghil-call> env loc proc args)
17e90c5e 374 ;; PROC
3616e9e9 375 ;; ARGS...
17e90c5e 376 ;; ([tail-]call NARGS)
17e90c5e 377 (comp-push proc)
f03c31db 378 (push-call! loc (if tail 'goto/args 'call) args)
efbd5892
AW
379 (maybe-drop))
380
381 ((<ghil-mv-call> env loc producer consumer)
382 ;; CONSUMER
383 ;; PRODUCER
384 ;; (mv-call MV)
385 ;; ([tail]-call 1)
386 ;; goto POST
387 ;; MV: [tail-]call/nargs
388 ;; POST: (maybe-drop)
389 (let ((MV (make-label)) (POST (make-label)))
390 (comp-push consumer)
391 (comp-push producer)
392 (push-code! loc (make-glil-mv-call 0 MV))
393 (push-code! loc (make-glil-call (if tail 'goto/args 'call) 1))
394 (cond ((not tail)
395 (push-branch! #f 'br POST)))
396 (push-label! MV)
397 (push-code! loc (make-glil-call (if tail 'goto/nargs 'call/nargs) 0))
398 (cond ((not tail)
399 (push-label! POST)
20bdc710
AW
400 (maybe-drop)))))
401
402 ((<ghil-reified-env> env loc)
403 (return-object! loc (ghil-env-reify env)))))
404
17e90c5e
KN
405 ;;
406 ;; main
67169b29 407 (record-case ghil
fbde2b91 408 ((<ghil-lambda> env loc vars rest meta body)
f540e327
AW
409 (let* ((evars (ghil-env-variables env))
410 (locs (pick (lambda (v) (eq? (ghil-var-kind v) 'local)) evars))
411 (exts (pick (lambda (v) (eq? (ghil-var-kind v) 'external)) evars)))
17e90c5e 412 ;; initialize variable indexes
f540e327 413 (finalize-index! vars)
17e90c5e
KN
414 (finalize-index! locs)
415 (finalize-index! exts)
ac99cb0c 416 ;; meta bindings
96969dc1 417 (push-bindings! #f vars)
17e90c5e 418 ;; export arguments
061f7fae 419 (do ((n 0 (1+ n))
f540e327 420 (l vars (cdr l)))
17e90c5e
KN
421 ((null? l))
422 (let ((v (car l)))
aa0a011b
AW
423 (case (ghil-var-kind v)
424 ((external)
96969dc1
AW
425 (push-code! #f (make-glil-argument 'ref n))
426 (push-code! #f (make-glil-external 'set 0 (ghil-var-index v)))))))
17e90c5e
KN
427 ;; compile body
428 (comp body #t #f)
429 ;; create GLIL
1a1a10d3
AW
430 (let ((vars (make-glil-vars #:nargs (length vars)
431 #:nrest (if rest 1 0)
432 #:nlocs (length locs)
433 #:nexts (length exts))))
fbde2b91 434 (make-glil-asm vars meta (reverse! stack))))))))
17e90c5e
KN
435
436(define (finalize-index! list)
437 (do ((n 0 (1+ n))
438 (l list (cdr l)))
439 ((null? l))
aa0a011b 440 (let ((v (car l))) (set! (ghil-var-index v) n))))