use #:keywords in module/*.scm, not :keywords
[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
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)
22bcbe8c 44 (make-ghil-if env loc (optimize test) (optimize then) (optimize else)))
3616e9e9 45
61dc81d9 46 ((<ghil-begin> env loc exps)
22bcbe8c 47 (make-ghil-begin env loc (map optimize exps)))
3616e9e9 48
61dc81d9 49 ((<ghil-bind> env loc vars vals body)
22bcbe8c 50 (make-ghil-bind env loc vars (map optimize vals) (optimize body)))
3616e9e9 51
fbde2b91
AW
52 ((<ghil-lambda> env loc vars rest meta body)
53 (make-ghil-lambda env loc vars rest meta (optimize body)))
3616e9e9 54
22bcbe8c
AW
55 ((<ghil-inline> env loc instruction args)
56 (make-ghil-inline env loc instruction (map optimize args)))
3616e9e9 57
61dc81d9
AW
58 ((<ghil-call> env loc proc args)
59 (let ((parent-env env))
60 (record-case proc
61 ;; ((@lambda (VAR...) BODY...) ARG...) =>
62 ;; (@let ((VAR ARG) ...) BODY...)
fbde2b91 63 ((<ghil-lambda> env loc vars rest meta body)
61dc81d9
AW
64 (cond
65 ((not rest)
66 (for-each (lambda (v)
67 (case (ghil-var-kind v)
68 ((argument) (set! (ghil-var-kind v) 'local)))
69 (set! (ghil-var-env v) parent-env)
70 (ghil-env-add! parent-env v))
71 (ghil-env-variables env)))
72 (else
22bcbe8c 73 (make-ghil-call parent-env loc (optimize proc) (map optimize args)))))
61dc81d9 74 (else
22bcbe8c 75 (make-ghil-call parent-env loc (optimize proc) (map optimize args))))))
61dc81d9 76
17e90c5e
KN
77 (else x)))
78
79\f
80;;;
81;;; Stage 3: Code generation
82;;;
83
849cefac
AW
84(define *ia-void* (make-glil-void))
85(define *ia-drop* (make-glil-call 'drop 0))
86(define *ia-return* (make-glil-call 'return 0))
17e90c5e
KN
87
88(define (make-label) (gensym ":L"))
89
90(define (make-glil-var op env var)
aa0a011b 91 (case (ghil-var-kind var)
17e90c5e 92 ((argument)
aa0a011b 93 (make-glil-argument op (ghil-var-index var)))
17e90c5e 94 ((local)
aa0a011b 95 (make-glil-local op (ghil-var-index var)))
17e90c5e
KN
96 ((external)
97 (do ((depth 0 (1+ depth))
aa0a011b
AW
98 (e env (ghil-env-parent e)))
99 ((eq? e (ghil-var-env var))
100 (make-glil-external op depth (ghil-var-index var)))))
17e90c5e 101 ((module)
2e7e6969 102 (make-glil-module op (ghil-var-env var) (ghil-var-name var)))
17e90c5e
KN
103 (else (error "Unknown kind of variable:" var))))
104
1b79210a
AW
105(define (constant? x)
106 (cond ((or (number? x) (string? x) (symbol? x) (keyword? x) (boolean? x)) #t)
107 ((pair? x) (and (constant? (car x))
108 (constant? (cdr x))))
109 ((vector? x) (let lp ((i (vector-length x)))
110 (or (zero? i)
111 (and (constant? (vector-ref x (1- i)))
112 (lp (1- i))))))))
113
17e90c5e
KN
114(define (codegen ghil)
115 (let ((stack '()))
96969dc1 116 (define (push-code! loc code)
d0168f3d
AW
117 (set! stack (cons code stack))
118 (if loc (set! stack (cons (make-glil-source loc) stack))))
96969dc1 119 (define (push-bindings! loc vars)
aa0a011b
AW
120 (if (not (null? vars))
121 (push-code!
96969dc1 122 loc
aa0a011b
AW
123 (make-glil-bind
124 (map list
125 (map ghil-var-name vars)
126 (map ghil-var-kind vars)
127 (map ghil-var-index vars))))))
17e90c5e 128 (define (comp tree tail drop)
cb4cca12 129 (define (push-label! label)
96969dc1
AW
130 (push-code! #f (make-glil-label label)))
131 (define (push-branch! loc inst label)
132 (push-code! loc (make-glil-branch inst label)))
ac99cb0c 133 (define (push-call! loc inst args)
cb4cca12 134 (for-each comp-push args)
96969dc1 135 (push-code! loc (make-glil-call inst (length args))))
17e90c5e
KN
136 ;; possible tail position
137 (define (comp-tail tree) (comp tree tail drop))
138 ;; push the result
139 (define (comp-push tree) (comp tree #f #f))
140 ;; drop the result
141 (define (comp-drop tree) (comp tree #f #t))
cb4cca12
KN
142 ;; drop the result if unnecessary
143 (define (maybe-drop)
96969dc1 144 (if drop (push-code! #f *ia-drop*)))
cb4cca12
KN
145 ;; return here if necessary
146 (define (maybe-return)
96969dc1 147 (if tail (push-code! #f *ia-return*)))
17e90c5e 148 ;; return this code if necessary
96969dc1
AW
149 (define (return-code! loc code)
150 (if (not drop) (push-code! loc code))
cb4cca12 151 (maybe-return))
17e90c5e 152 ;; return void if necessary
cb4cca12 153 (define (return-void!)
96969dc1 154 (return-code! #f *ia-void*))
cb4cca12 155 ;; return object if necessary
96969dc1
AW
156 (define (return-object! loc obj)
157 (return-code! loc (make-glil-const #:obj obj)))
17e90c5e
KN
158 ;;
159 ;; dispatch
67169b29
AW
160 (record-case tree
161 ((<ghil-void>)
17e90c5e
KN
162 (return-void!))
163
67169b29 164 ((<ghil-quote> env loc obj)
96969dc1 165 (return-object! loc obj))
cb4cca12 166
67169b29 167 ((<ghil-quasiquote> env loc exp)
cb4cca12 168 (let loop ((x exp))
67169b29
AW
169 (cond
170 ((list? x)
171 (push-call! #f 'mark '())
172 (for-each loop x)
173 (push-call! #f 'list-mark '()))
174 ((pair? x)
175 (loop (car x))
176 (loop (cdr x))
96969dc1 177 (push-code! #f (make-glil-call 'cons 2)))
67169b29
AW
178 ((record? x)
179 (record-case x
180 ((<ghil-unquote> env loc exp)
181 (comp-push exp))
182 ((<ghil-unquote-splicing> env loc exp)
183 (comp-push exp)
184 (push-call! #f 'list-break '()))))
1b79210a
AW
185 ((constant? x)
186 (push-code! #f (make-glil-const #:obj x)))
67169b29 187 (else
1b79210a 188 (error "element of quasiquote can't be compiled" x))))
cb4cca12
KN
189 (maybe-drop)
190 (maybe-return))
17e90c5e 191
67169b29 192 ((<ghil-ref> env loc var)
96969dc1 193 (return-code! loc (make-glil-var 'ref env var)))
17e90c5e 194
67169b29 195 ((<ghil-set> env loc var val)
ac99cb0c 196 (comp-push val)
96969dc1 197 (push-code! loc (make-glil-var 'set env var))
ac99cb0c
KN
198 (return-void!))
199
67169b29 200 ((<ghil-define> env loc var val)
17e90c5e 201 (comp-push val)
96969dc1 202 (push-code! loc (make-glil-var 'define env var))
17e90c5e
KN
203 (return-void!))
204
67169b29 205 ((<ghil-if> env loc test then else)
17e90c5e
KN
206 ;; TEST
207 ;; (br-if-not L1)
208 ;; THEN
41f248a8 209 ;; (br L2)
17e90c5e
KN
210 ;; L1: ELSE
211 ;; L2:
212 (let ((L1 (make-label)) (L2 (make-label)))
213 (comp-push test)
96969dc1 214 (push-branch! loc 'br-if-not L1)
17e90c5e 215 (comp-tail then)
96969dc1 216 (if (not tail) (push-branch! #f 'br L2))
cb4cca12 217 (push-label! L1)
17e90c5e 218 (comp-tail else)
cb4cca12
KN
219 (if (not tail) (push-label! L2))))
220
67169b29 221 ((<ghil-and> env loc exps)
cb4cca12
KN
222 ;; EXP
223 ;; (br-if-not L1)
224 ;; ...
225 ;; TAIL
226 ;; (br L2)
227 ;; L1: (const #f)
228 ;; L2:
7e4760e4
AW
229 (cond ((null? exps) (return-object! loc #t))
230 ((null? (cdr exps)) (comp-tail (car exps)))
231 (else
232 (let ((L1 (make-label)) (L2 (make-label)))
233 (let lp ((exps exps))
234 (cond ((null? (cdr exps))
235 (comp-tail (car exps))
236 (push-branch! #f 'br L2)
237 (push-label! L1)
238 (return-object! #f #f)
239 (push-label! L2)
240 (maybe-return))
241 (else
242 (comp-push (car exps))
243 (push-branch! #f 'br-if-not L1)
244 (lp (cdr exps)))))))))
cb4cca12 245
67169b29 246 ((<ghil-or> env loc exps)
cb4cca12
KN
247 ;; EXP
248 ;; (dup)
249 ;; (br-if L1)
250 ;; (drop)
251 ;; ...
252 ;; TAIL
253 ;; L1:
7e4760e4
AW
254 (cond ((null? exps) (return-object! loc #f))
255 ((null? (cdr exps)) (comp-tail (car exps)))
256 (else
257 (let ((L1 (make-label)))
258 (let lp ((exps exps))
259 (cond ((null? (cdr exps))
260 (comp-tail (car exps))
261 (push-label! L1)
262 (maybe-return))
263 (else
264 (comp-push (car exps))
265 (push-call! #f 'dup '())
266 (push-branch! #f 'br-if L1)
267 (push-call! #f 'drop '())
268 (lp (cdr exps)))))))))
17e90c5e 269
67169b29 270 ((<ghil-begin> env loc exps)
17e90c5e
KN
271 ;; EXPS...
272 ;; TAIL
273 (if (null? exps)
274 (return-void!)
275 (do ((exps exps (cdr exps)))
276 ((null? (cdr exps))
277 (comp-tail (car exps)))
278 (comp-drop (car exps)))))
279
67169b29 280 ((<ghil-bind> env loc vars vals body)
17e90c5e
KN
281 ;; VALS...
282 ;; (set VARS)...
283 ;; BODY
284 (for-each comp-push vals)
96969dc1
AW
285 (push-bindings! loc vars)
286 (for-each (lambda (var) (push-code! #f (make-glil-var 'set env var)))
a6df585a 287 (reverse vars))
ac99cb0c 288 (comp-tail body)
96969dc1 289 (push-code! #f (make-glil-unbind)))
17e90c5e 290
fbde2b91 291 ((<ghil-lambda> env loc vars rest meta body)
96969dc1 292 (return-code! loc (codegen tree)))
17e90c5e 293
f540e327 294 ((<ghil-inline> env loc inline args)
46cd9a34
KN
295 ;; ARGS...
296 ;; (INST NARGS)
f540e327 297 (push-call! loc inline args)
cb4cca12
KN
298 (maybe-drop)
299 (maybe-return))
46cd9a34 300
67169b29 301 ((<ghil-call> env loc proc args)
17e90c5e 302 ;; PROC
3616e9e9 303 ;; ARGS...
17e90c5e 304 ;; ([tail-]call NARGS)
17e90c5e 305 (comp-push proc)
ac99cb0c 306 (push-call! loc (if tail 'tail-call 'call) args)
cb4cca12 307 (maybe-drop))))
17e90c5e
KN
308 ;;
309 ;; main
67169b29 310 (record-case ghil
fbde2b91 311 ((<ghil-lambda> env loc vars rest meta body)
f540e327
AW
312 (let* ((evars (ghil-env-variables env))
313 (locs (pick (lambda (v) (eq? (ghil-var-kind v) 'local)) evars))
314 (exts (pick (lambda (v) (eq? (ghil-var-kind v) 'external)) evars)))
17e90c5e 315 ;; initialize variable indexes
f540e327 316 (finalize-index! vars)
17e90c5e
KN
317 (finalize-index! locs)
318 (finalize-index! exts)
ac99cb0c 319 ;; meta bindings
96969dc1 320 (push-bindings! #f vars)
17e90c5e 321 ;; export arguments
061f7fae 322 (do ((n 0 (1+ n))
f540e327 323 (l vars (cdr l)))
17e90c5e
KN
324 ((null? l))
325 (let ((v (car l)))
aa0a011b
AW
326 (case (ghil-var-kind v)
327 ((external)
96969dc1
AW
328 (push-code! #f (make-glil-argument 'ref n))
329 (push-code! #f (make-glil-external 'set 0 (ghil-var-index v)))))))
17e90c5e
KN
330 ;; compile body
331 (comp body #t #f)
332 ;; create GLIL
1a1a10d3
AW
333 (let ((vars (make-glil-vars #:nargs (length vars)
334 #:nrest (if rest 1 0)
335 #:nlocs (length locs)
336 #:nexts (length exts))))
fbde2b91 337 (make-glil-asm vars meta (reverse! stack))))))))
17e90c5e
KN
338
339(define (finalize-index! list)
340 (do ((n 0 (1+ n))
341 (l list (cdr l)))
342 ((null? l))
aa0a011b 343 (let ((v (car l))) (set! (ghil-var-index v) n))))