1 ;;; TREE-IL -> GLIL compiler
3 ;; Copyright (C) 2001,2008,2009 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 (language tree-il compile-glil)
23 #:use-module (system base syntax)
24 #:use-module (ice-9 receive)
25 #:use-module (language glil)
26 #:use-module (language tree-il)
27 #:use-module (language tree-il optimize)
28 #:use-module (language tree-il analyze)
29 #:export (compile-glil))
33 ;; call-with-values -> mv-bind
34 ;; compile-time-environment
35 ;; basic degenerate-case reduction
38 ;; sym -> (local . index) | (heap level . index)
39 ;; lambda -> (nlocs . nexts)
41 (define *comp-module* (make-fluid))
43 (define (compile-glil x e opts)
44 (let* ((x (make-lambda (tree-il-src x) '() '() '() x))
45 (x (optimize! x e opts))
46 (allocation (analyze-lexicals x)))
47 (with-fluid* *comp-module* (or (and e (car e)) (current-module))
49 (values (flatten-lambda x -1 allocation)
50 (and e (cons (car e) (cddr e)))
55 (define *primcall-ops* (make-hash-table))
57 (lambda (x) (hash-set! *primcall-ops* (car x) (cdr x)))
60 ((equal? . 2) . equal?)
70 ((quotient . 2) . quo)
71 ((remainder . 2) . rem)
78 ((set-car! . 2) . set-car!)
79 ((set-cdr! . 2) . set-cdr!)
84 ((@slot-ref . 2) . slot-ref)
85 ((@slot-set! . 3) . slot-set)))
87 (define (make-label) (gensym ":L"))
89 (define (vars->bind-list ids vars allocation)
91 (let ((loc (hashq-ref allocation v)))
93 ((stack) (list id 'local (cdr loc)))
94 ((heap) (list id 'external (cddr loc)))
95 (else (error "badness" id v loc)))))
99 (define (emit-bindings src ids vars allocation emit-code)
101 (emit-code src (make-glil-bind
102 (vars->bind-list ids vars allocation)))))
104 (define (with-output-to-code proc)
106 (define (emit-code src x)
107 (set! out (cons x out))
109 (set! out (cons (make-glil-source src) out))))
113 (define (flatten-lambda x level allocation)
114 (receive (ids vars nargs nrest)
115 (let lp ((ids (lambda-names x)) (vars (lambda-vars x))
116 (oids '()) (ovars '()) (n 0))
117 (cond ((null? vars) (values (reverse oids) (reverse ovars) n 0))
118 ((pair? vars) (lp (cdr ids) (cdr vars)
119 (cons (car ids) oids) (cons (car vars) ovars)
121 (else (values (reverse (cons ids oids))
122 (reverse (cons vars ovars))
124 (let ((nlocs (car (hashq-ref allocation x)))
125 (nexts (cdr (hashq-ref allocation x))))
127 nargs nrest nlocs nexts (lambda-meta x)
130 ;; write bindings and source debugging info
131 (emit-bindings #f ids vars allocation emit-code)
133 (emit-code (make-glil-src (lambda-src x))))
135 ;; copy args to the heap if necessary
136 (let lp ((in vars) (n 0))
138 (let ((loc (hashq-ref allocation (car in))))
141 (emit-code #f (make-glil-local 'ref n))
142 (emit-code #f (make-glil-external 'set 0 (cddr loc)))))
143 (lp (cdr in) (1+ n)))))
145 ;; and here, here, dear reader: we compile.
146 (flatten (lambda-body x) (1+ level) allocation emit-code)))))))
148 (define (flatten x level allocation emit-code)
149 (define (emit-label label)
150 (emit-code #f (make-glil-label label)))
151 (define (emit-branch src inst label)
152 (emit-code src (make-glil-branch inst label)))
154 (let comp ((x x) (context 'tail))
155 (define (comp-tail tree) (comp tree context))
156 (define (comp-push tree) (comp tree 'push))
157 (define (comp-drop tree) (comp tree 'drop))
162 ((push) (emit-code #f (make-glil-void)))
164 (emit-code #f (make-glil-void))
165 (emit-code #f (make-glil-call 'return 1)))))
169 ((push) (emit-code src (make-glil-const exp)))
171 (emit-code src (make-glil-const exp))
172 (emit-code #f (make-glil-call 'return 1)))))
174 ;; FIXME: should represent sequence as exps tail
175 ((<sequence> src exps)
176 (let lp ((exps exps))
177 (if (null? (cdr exps))
178 (comp-tail (car exps))
180 (comp-drop (car exps))
183 ((<application> src proc args)
184 ;; FIXME: need a better pattern-matcher here
186 ((and (primitive-ref? proc)
187 (eq? (primitive-ref-name proc) '@apply)
188 (>= (length args) 2))
189 (let ((proc (car args))
192 ((and (primitive-ref? proc) (eq? (primitive-ref-name proc) 'values)
193 (not (eq? context 'push)))
194 ;; tail: (lambda () (apply values '(1 2)))
195 ;; drop: (lambda () (apply values '(1 2)) 3)
196 ;; push: (lambda () (list (apply values '(10 12)) 1))
198 ((drop) (for-each comp-drop args))
200 (for-each comp-push args)
201 (emit-code src (make-glil-call 'return/values* (length args))))))
205 (for-each comp-push args)
207 ((drop) (emit-code src (make-glil-call 'apply (1+ (length args))))
208 (emit-code src (make-glil-call 'drop 1)))
209 ((tail) (emit-code src (make-glil-call 'goto/apply (1+ (length args)))))
210 ((push) (emit-code src (make-glil-call 'apply (1+ (length args))))))))))
212 ((and (primitive-ref? proc) (eq? (primitive-ref-name proc) 'values)
213 (not (eq? context 'push)))
214 ;; tail: (lambda () (values '(1 2)))
215 ;; drop: (lambda () (values '(1 2)) 3)
216 ;; push: (lambda () (list (values '(10 12)) 1))
218 ((drop) (for-each comp-drop args))
220 (for-each comp-push args)
221 (emit-code src (make-glil-call 'return/values (length args))))))
222 ((and (primitive-ref? proc)
223 (eq? (primitive-ref-name proc) '@call-with-values)
230 ;; MV: [tail-]call/nargs
231 ;; POST: (maybe-drop)
232 (let ((MV (make-label)) (POST (make-label))
233 (producer (car args)) (consumer (cadr args)))
236 (emit-code src (make-glil-mv-call 0 MV))
238 ((tail) (emit-code src (make-glil-call 'goto/args 1)))
239 (else (emit-code src (make-glil-call 'call 1))
240 (emit-branch #f 'br POST)))
243 ((tail) (emit-code src (make-glil-call 'goto/nargs 0)))
244 (else (emit-code src (make-glil-call 'call/nargs 0))
246 (if (eq? context 'drop)
247 (emit-code #f (make-glil-call 'drop 1)))))))
249 ((and (primitive-ref? proc)
250 (eq? (primitive-ref-name proc) '@call-with-current-continuation)
252 (comp-push (car args))
254 ((tail) (emit-code src (make-glil-call 'goto/cc 1)))
255 ((push) (emit-code src (make-glil-call 'call/cc 1)))
256 ((drop) (emit-code src (make-glil-call 'call/cc 1))
257 (emit-code src (make-glil-call 'drop 1)))))
259 ((and (primitive-ref? proc)
260 (or (hash-ref *primcall-ops*
261 (cons (primitive-ref-name proc) (length args)))
262 (hash-ref *primcall-ops* (primitive-ref-name proc))))
264 (for-each comp-push args)
265 (emit-code src (make-glil-call op (length args)))
267 ((tail) (emit-code #f (make-glil-call 'return 1)))
268 ((drop) (emit-code #f (make-glil-call 'drop 1))))))
271 (for-each comp-push args)
272 (let ((len (length args)))
274 ((tail) (emit-code src (make-glil-call 'goto/args len)))
275 ((push) (emit-code src (make-glil-call 'call len)))
276 ((drop) (emit-code src (make-glil-call 'call len))
277 (emit-code src (make-glil-call 'drop 1))))))))
279 ((<conditional> src test then else)
286 (let ((L1 (make-label)) (L2 (make-label)))
288 (emit-branch src 'br-if-not L1)
290 (if (not (eq? context 'tail))
291 (emit-branch #f 'br L2))
294 (if (not (eq? context 'tail))
297 ((<primitive-ref> src name)
299 ((eq? (module-variable (fluid-ref *comp-module*) name)
300 (module-variable the-root-module name))
303 (emit-code src (make-glil-toplevel 'ref name)))
305 (emit-code src (make-glil-toplevel 'ref name))
306 (emit-code #f (make-glil-call 'return 1)))))
308 (pk 'ew-the-badness x (current-module) (fluid-ref *comp-module*))
311 (emit-code src (make-glil-module 'ref '(guile) name #f)))
313 (emit-code src (make-glil-module 'ref '(guile) name #f))
314 (emit-code #f (make-glil-call 'return 1)))))))
316 ((<lexical-ref> src name gensym)
319 (let ((loc (hashq-ref allocation gensym)))
322 (emit-code src (make-glil-local 'ref (cdr loc))))
324 (emit-code src (make-glil-external
325 'ref (- level (cadr loc)) (cddr loc))))
326 (else (error "badness" x loc)))
327 (if (eq? context 'tail)
328 (emit-code #f (make-glil-call 'return 1)))))))
330 ((<lexical-set> src name gensym exp)
332 (let ((loc (hashq-ref allocation gensym)))
335 (emit-code src (make-glil-local 'set (cdr loc))))
337 (emit-code src (make-glil-external
338 'set (- level (cadr loc)) (cddr loc))))
339 (else (error "badness" x loc))))
342 (emit-code #f (make-glil-void)))
344 (emit-code #f (make-glil-void))
345 (emit-code #f (make-glil-call 'return 1)))))
347 ((<module-ref> src mod name public?)
348 (emit-code src (make-glil-module 'ref mod name public?))
350 ((drop) (emit-code #f (make-glil-call 'drop 1)))
351 ((tail) (emit-code #f (make-glil-call 'return 1)))))
353 ((<module-set> src mod name public? exp)
355 (emit-code src (make-glil-module 'set mod name public?))
358 (emit-code #f (make-glil-void)))
360 (emit-code #f (make-glil-void))
361 (emit-code #f (make-glil-call 'return 1)))))
363 ((<toplevel-ref> src name)
364 (emit-code src (make-glil-toplevel 'ref name))
366 ((drop) (emit-code #f (make-glil-call 'drop 1)))
367 ((tail) (emit-code #f (make-glil-call 'return 1)))))
369 ((<toplevel-set> src name exp)
371 (emit-code src (make-glil-toplevel 'set name))
374 (emit-code #f (make-glil-void)))
376 (emit-code #f (make-glil-void))
377 (emit-code #f (make-glil-call 'return 1)))))
379 ((<toplevel-define> src name exp)
381 (emit-code src (make-glil-toplevel 'define name))
384 (emit-code #f (make-glil-void)))
386 (emit-code #f (make-glil-void))
387 (emit-code #f (make-glil-call 'return 1)))))
392 (emit-code #f (flatten-lambda x level allocation)))
394 (emit-code #f (flatten-lambda x level allocation))
395 (emit-code #f (make-glil-call 'return 1)))))
397 ((<let> src names vars vals exp)
398 (for-each comp-push vals)
399 (emit-bindings src names vars allocation emit-code)
400 (for-each (lambda (v)
401 (let ((loc (hashq-ref allocation v)))
404 (emit-code src (make-glil-local 'set (cdr loc))))
406 (emit-code src (make-glil-external 'set 0 (cddr loc))))
407 (else (error "badness" x loc)))))
410 (emit-code #f (make-glil-unbind)))
412 ((<letrec> src names vars vals exp)
413 (for-each comp-push vals)
414 (emit-bindings src names vars allocation emit-code)
415 (for-each (lambda (v)
416 (let ((loc (hashq-ref allocation v)))
419 (emit-code src (make-glil-local 'set (cdr loc))))
421 (emit-code src (make-glil-external 'set 0 (cddr loc))))
422 (else (error "badness" x loc)))))
425 (emit-code #f (make-glil-unbind))))))