1 ;;; GHIL -> GLIL compiler
3 ;; Copyright (C) 2001 Free Software Foundation, Inc.
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)
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.
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.
22 (define-module (system il compile)
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)
29 (define (compile x e . opts)
30 (if (memq :O opts) (set! x (optimize x)))
35 ;;; Stage 2: Optimization
40 ((<ghil-set> env loc var val)
41 (make-ghil-set env var (optimize val)))
43 ((<ghil-if> env loc test then else)
44 (make-ghil-if env loc (optimize test) (optimize then) (optimize else)))
46 ((<ghil-begin> env loc exps)
47 (make-ghil-begin env loc (map optimize exps)))
49 ((<ghil-bind> env loc vars vals body)
50 (make-ghil-bind env loc vars (map optimize vals) (optimize body)))
52 ((<ghil-lambda> env loc vars rest meta body)
53 (make-ghil-lambda env loc vars rest meta (optimize body)))
55 ((<ghil-inline> env loc instruction args)
56 (make-ghil-inline env loc instruction (map optimize args)))
58 ((<ghil-call> env loc proc args)
59 (let ((parent-env env))
61 ;; ((@lambda (VAR...) BODY...) ARG...) =>
62 ;; (@let ((VAR ARG) ...) BODY...)
63 ((<ghil-lambda> env loc vars rest meta body)
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)))
73 (make-ghil-call parent-env loc (optimize proc) (map optimize args)))))
75 (make-ghil-call parent-env loc (optimize proc) (map optimize args))))))
81 ;;; Stage 3: Code generation
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))
88 (define (make-label) (gensym ":L"))
90 (define (make-glil-var op env var)
91 (case (ghil-var-kind var)
93 (make-glil-argument op (ghil-var-index var)))
95 (make-glil-local op (ghil-var-index var)))
97 (do ((depth 0 (1+ depth))
98 (e env (ghil-env-parent e)))
99 ((eq? e (ghil-var-env var))
100 (make-glil-external op depth (ghil-var-index var)))))
102 (let ((env (ghil-var-env var)))
103 (make-glil-module op (ghil-mod-module (ghil-env-mod env))
104 (ghil-var-name var))))
105 (else (error "Unknown kind of variable:" var))))
107 (define (codegen ghil)
109 (define (push-code! loc code)
110 (set! stack (cons code stack))
111 (if loc (set! stack (cons (make-glil-source loc) stack))))
112 (define (push-bindings! loc vars)
113 (if (not (null? vars))
118 (map ghil-var-name vars)
119 (map ghil-var-kind vars)
120 (map ghil-var-index vars))))))
121 (define (comp tree tail drop)
122 (define (push-label! label)
123 (push-code! #f (make-glil-label label)))
124 (define (push-branch! loc inst label)
125 (push-code! loc (make-glil-branch inst label)))
126 (define (push-call! loc inst args)
127 (for-each comp-push args)
128 (push-code! loc (make-glil-call inst (length args))))
129 ;; possible tail position
130 (define (comp-tail tree) (comp tree tail drop))
132 (define (comp-push tree) (comp tree #f #f))
134 (define (comp-drop tree) (comp tree #f #t))
135 ;; drop the result if unnecessary
137 (if drop (push-code! #f *ia-drop*)))
138 ;; return here if necessary
139 (define (maybe-return)
140 (if tail (push-code! #f *ia-return*)))
141 ;; return this code if necessary
142 (define (return-code! loc code)
143 (if (not drop) (push-code! loc code))
145 ;; return void if necessary
146 (define (return-void!)
147 (return-code! #f *ia-void*))
148 ;; return object if necessary
149 (define (return-object! loc obj)
150 (return-code! loc (make-glil-const #:obj obj)))
157 ((<ghil-quote> env loc obj)
158 (return-object! loc obj))
160 ((<ghil-quasiquote> env loc exp)
164 (push-call! #f 'mark '())
166 (push-call! #f 'list-mark '()))
170 (push-code! #f (make-glil-call 'cons 2)))
173 ((<ghil-unquote> env loc exp)
175 ((<ghil-unquote-splicing> env loc exp)
177 (push-call! #f 'list-break '()))))
179 (push-code! #f (make-glil-const #:obj x)))))
183 ((<ghil-ref> env loc var)
184 (return-code! loc (make-glil-var 'ref env var)))
186 ((<ghil-set> env loc var val)
188 (push-code! loc (make-glil-var 'set env var))
191 ((<ghil-define> env loc var val)
193 (push-code! loc (make-glil-var 'define env var))
196 ((<ghil-if> env loc test then else)
203 (let ((L1 (make-label)) (L2 (make-label)))
205 (push-branch! loc 'br-if-not L1)
207 (if (not tail) (push-branch! #f 'br L2))
210 (if (not tail) (push-label! L2))))
212 ((<ghil-and> env loc exps)
220 (cond ((null? exps) (return-object! loc #t))
221 ((null? (cdr exps)) (comp-tail (car exps)))
223 (let ((L1 (make-label)) (L2 (make-label)))
224 (let lp ((exps exps))
225 (cond ((null? (cdr exps))
226 (comp-tail (car exps))
227 (push-branch! #f 'br L2)
229 (return-object! #f #f)
233 (comp-push (car exps))
234 (push-branch! #f 'br-if-not L1)
235 (lp (cdr exps)))))))))
237 ((<ghil-or> env loc exps)
245 (cond ((null? exps) (return-object! loc #f))
246 ((null? (cdr exps)) (comp-tail (car exps)))
248 (let ((L1 (make-label)))
249 (let lp ((exps exps))
250 (cond ((null? (cdr exps))
251 (comp-tail (car exps))
255 (comp-push (car exps))
256 (push-call! #f 'dup '())
257 (push-branch! #f 'br-if L1)
258 (push-call! #f 'drop '())
259 (lp (cdr exps)))))))))
261 ((<ghil-begin> env loc exps)
266 (do ((exps exps (cdr exps)))
268 (comp-tail (car exps)))
269 (comp-drop (car exps)))))
271 ((<ghil-bind> env loc vars vals body)
275 (for-each comp-push vals)
276 (push-bindings! loc vars)
277 (for-each (lambda (var) (push-code! #f (make-glil-var 'set env var)))
280 (push-code! #f (make-glil-unbind)))
282 ((<ghil-lambda> env loc vars rest meta body)
283 (return-code! loc (codegen tree)))
285 ((<ghil-inline> env loc inline args)
288 (push-call! loc inline args)
292 ((<ghil-call> env loc proc args)
295 ;; ([tail-]call NARGS)
297 (push-call! loc (if tail 'tail-call 'call) args)
302 ((<ghil-lambda> env loc vars rest meta body)
303 (let* ((evars (ghil-env-variables env))
304 (locs (pick (lambda (v) (eq? (ghil-var-kind v) 'local)) evars))
305 (exts (pick (lambda (v) (eq? (ghil-var-kind v) 'external)) evars)))
306 ;; initialize variable indexes
307 (finalize-index! vars)
308 (finalize-index! locs)
309 (finalize-index! exts)
311 (push-bindings! #f vars)
317 (case (ghil-var-kind v)
319 (push-code! #f (make-glil-argument 'ref n))
320 (push-code! #f (make-glil-external 'set 0 (ghil-var-index v)))))))
324 (let ((vars (make-glil-vars :nargs (length vars)
327 :nexts (length exts))))
328 (make-glil-asm vars meta (reverse! stack))))))))
330 (define (finalize-index! list)
334 (let ((v (car l))) (set! (ghil-var-index v) n))))