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 (language glil compile-assembly)
23 #:use-module (system base syntax)
24 #:use-module (system base pmatch)
25 #:use-module (language glil)
26 #:use-module (language assembly)
27 #:use-module (system vm instruction)
28 #:use-module ((system vm program) #:select (make-binding))
29 #:use-module (system vm conv) ;; fixme: move this module
30 #:use-module (ice-9 receive)
31 #:use-module ((srfi srfi-1) #:select (fold))
32 #:export (compile-assembly))
34 ;; Variable cache cells go in the object table, and serialize as their
35 ;; keys. The reason we wrap the keys in these records is so they don't
36 ;; compare as `equal?' to other objects in the object table.
38 ;; `key' is either a symbol or the list (MODNAME SYM PUBLIC?)
40 (define-record <variable-cache-cell> key)
42 ;; Subprograms can be loaded into an object table as well. We need a
43 ;; disjoint type here too.
45 (define-record <subprogram> code)
48 ;; A metadata thunk has no object table, so it is very quick to load.
49 (define (make-meta bindings sources tail)
50 (if (and (null? bindings) (null? sources) (null? tail))
54 (make-glil-program 0 0 0 0 #f
56 (make-glil-const `(,bindings ,sources ,@tail))
57 (make-glil-call 'return 0)))))))
59 ;; A functional stack of names of live variables.
60 (define (make-open-binding name ext? index)
61 (list name ext? index))
62 (define (make-closed-binding open-binding start end)
63 (make-binding (car open-binding) (cadr open-binding)
64 (caddr open-binding) start end))
65 (define (open-binding bindings vars nargs start)
71 ((,name argument ,i) (make-open-binding name #f i))
72 ((,name local ,i) (make-open-binding name #f (+ nargs i)))
73 ((,name external ,i) (make-open-binding name #t i))
74 (else (error "unknown binding type" name type))))
78 (define (close-binding bindings end)
80 ((((,start . ,closing) . ,open) . ,closed)
82 (fold (lambda (o tail)
83 ;; the cons is for dsu sort
84 (acons start (make-closed-binding o start end)
88 (else (error "broken bindings" bindings))))
89 (define (close-all-bindings bindings end)
90 (if (null? (car bindings))
92 (stable-sort (reverse (cdr bindings))
93 (lambda (x y) (< (car x) (car y)))))
94 (close-all-bindings (close-binding bindings end) end)))
96 ;; A functional object table.
97 (define *module-and-meta* 2)
98 (define (assoc-ref-or-acons x alist make-y)
99 (cond ((assoc-ref x alist)
100 => (lambda (y) (values y alist)))
102 (let ((y (make-y x alist)))
103 (values y (acons x y alist))))))
104 (define (object-index-and-alist x alist)
105 (assoc-ref-or-acons x alist
107 (+ (length alist) *module-and-meta*))))
109 (define (compile-assembly glil)
111 (glil->assembly glil 0 '() '(()) '() '() #f 0)
113 (define (make-object-table objects meta)
114 (and (or meta (not (null? objects)))
115 (list->vector (cons* #f meta objects))))
117 (define (glil->assembly glil nargs nexts-stack bindings
118 source-alist label-alist object-alist addr)
119 (define (emit-code x)
120 (values x bindings source-alist label-alist object-alist))
121 (define (emit-code/object x object-alist)
122 (values x bindings source-alist label-alist object-alist))
125 ((<glil-program> nargs nrest nlocs nexts meta body)
126 (define (process-body)
127 (let ((nexts-stack (cons nexts nexts-stack)))
128 (let lp ((body body) (code '()) (bindings '(())) (source-alist '())
129 (label-alist '()) (object-alist (if (null? (cdr nexts-stack)) #f '())) (addr 0))
132 (values (reverse code)
133 (close-all-bindings bindings addr)
134 (reverse source-alist)
135 (reverse label-alist)
136 (and object-alist (map car (reverse object-alist)))
139 (receive (subcode bindings source-alist label-alist object-alist)
140 (glil->assembly (car body) nargs nexts-stack bindings
141 source-alist label-alist object-alist addr)
142 (lp (cdr body) (append (reverse subcode) code)
143 bindings source-alist label-alist object-alist
144 (apply + addr (map byte-length subcode)))))))))
146 ;; include len and labels
147 (receive (code bindings sources labels objects subaddr)
149 (let ((asm `(,@(if objects
151 (make-object-table objects
152 (make-meta bindings sources meta))
155 (assembly ,nargs ,nrest ,nlocs ,nexts
158 ,@(if closure? '((make-closure)) '()))))
159 (cond ((or (null? nexts-stack) (not object-alist))
162 (receive (i object-alist)
163 (object-index-and-alist (make-subprogram asm) object-alist)
164 (emit-code/object '((object-ref ,i)) object-alist)))))))
168 (open-binding bindings vars nargs addr)
173 ((<glil-mv-bind> vars rest)
174 (values `((truncate-values ,(length vars) ,(if rest 1 0)))
175 (open-binding bindings vars nargs addr)
182 (close-binding bindings addr)
190 (acons addr loc source-alist)
195 (emit-code '((void))))
201 (emit-code (list code))))
203 (emit-code (dump-object obj addr)))
205 (receive (i object-alist)
206 (object-index-and-alist obj object-alist)
207 (emit-code/object `((object-ref ,i))
210 ((<glil-argument> op index)
211 (emit-code (if (eq? op 'ref)
212 `((local-ref ,index))
213 `((local-set ,index)))))
215 ((<glil-local> op index)
216 (emit-code (if (eq? op 'ref)
217 `((local-ref ,(+ nargs index)))
218 `((local-set ,(+ nargs index))))))
220 ((<glil-external> op depth index)
221 (emit-code (let lp ((d depth) (n 0) (stack nexts-stack))
223 (lp (1- d) (+ n (car stack)) (cdr stack))
225 `((external-ref ,(+ n index)))
226 `((external-set ,(+ n index))))))))
228 ((<glil-toplevel> op name)
233 (emit-code `(,@(dump-object name addr)
236 ((ref) '(variable-ref))
237 ((set) '(variable-set))))))
239 (receive (i object-alist)
240 (object-index-and-alist (make-variable-cache-cell name)
242 (emit-code/object (case op
243 ((ref) `((toplevel-ref ,i)))
244 ((set) `((toplevel-set ,i))))
247 (emit-code `((define ,(symbol->string name))
250 (error "unknown toplevel var kind" op name))))
252 ((<glil-module> op mod name public?)
253 (let ((key (list mod name public?)))
258 (emit-code `(,@(dump-object key addr)
261 ((ref) '(variable-ref))
262 ((set) '(variable-set))))))
264 (receive (i object-alist)
265 (object-index-and-alist (make-variable-cache-cell name)
267 (emit-code/object (case op
268 ((ref) `((toplevel-ref ,i)))
269 ((set) `((toplevel-set ,i))))
272 (error "unknown module var kind" op key)))))
274 ((<glil-label> label)
278 (acons label addr label-alist)
281 ((<glil-branch> inst label)
282 (emit-code `((,inst ,label))))
284 ;; nargs is number of stack args to insn. probably should rename.
285 ((<glil-call> inst nargs)
286 (if (not (instruction? inst))
287 (error "Unknown instruction:" inst))
288 (let ((pops (instruction-pops inst)))
290 (emit-code `((,inst ,nargs))))
292 (emit-code `((,inst))))
294 (error "Wrong number of stack arguments to instruction:" inst nargs)))))
296 ((<glil-mv-call> nargs ra)
297 (emit-code `((mv-call ,nargs ,ra))))))
299 ;; addr is currently unused, but could be used to align data in the
300 ;; instruction stream.
301 (define (dump-object x addr)
303 (error (string-append x " too long")))
307 ((object->code x) => list)
308 ((variable-cache-cell? x) (dump (variable-cache-cell-key x)))
309 ((subprogram? x) (list (subprogram-code x)))
310 ((and (integer? x) (exact? x))
311 (let ((str (do ((n x (quotient n 256))
312 (l '() (cons (modulo n 256) l)))
314 (apply u8vector l)))))
315 `((load-integer ,str))))
317 `((load-number ,(number->string x))))
321 `((load-symbol ,(symbol->string x))))
323 `((load-keyword ,(symbol->string (keyword->symbol x)))))
327 (let ((len (length x)))
328 (if (>= len 65536) (too-long "list"))
329 `((list ,(quotient len 256) ,(modulo len 256))))
338 (let ((len (vector-length x)))
339 (if (>= len 65536) (too-long "vector"))
340 `((vector ,(quotient len 256) ,(modulo len 256))))
343 (error "assemble: unrecognized object" x)))))