Commit | Line | Data |
---|---|---|
6e8ad823 AW |
1 | ;;; Continuation-passing style (CPS) intermediate language (IL) |
2 | ||
7ab76a83 | 3 | ;; Copyright (C) 2013, 2014 Free Software Foundation, Inc. |
6e8ad823 AW |
4 | |
5 | ;;;; This library is free software; you can redistribute it and/or | |
6 | ;;;; modify it under the terms of the GNU Lesser General Public | |
7 | ;;;; License as published by the Free Software Foundation; either | |
8 | ;;;; version 3 of the License, or (at your option) any later version. | |
9 | ;;;; | |
10 | ;;;; This library 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 GNU | |
13 | ;;;; Lesser General Public License for more details. | |
14 | ;;;; | |
15 | ;;;; You should have received a copy of the GNU Lesser General Public | |
16 | ;;;; License along with this library; if not, write to the Free Software | |
17 | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | ||
19 | ;;; Commentary: | |
20 | ;;; | |
691697de AW |
21 | ;;; Compiling CPS to bytecode. The result is in the bytecode language, |
22 | ;;; which happens to be an ELF image as a bytecode. | |
6e8ad823 AW |
23 | ;;; |
24 | ;;; Code: | |
25 | ||
691697de | 26 | (define-module (language cps compile-bytecode) |
6e8ad823 AW |
27 | #:use-module (ice-9 match) |
28 | #:use-module (srfi srfi-1) | |
29 | #:use-module (language cps) | |
30 | #:use-module (language cps arities) | |
31 | #:use-module (language cps closure-conversion) | |
8ac8e2df | 32 | #:use-module (language cps contification) |
fa3b6e57 | 33 | #:use-module (language cps constructors) |
7a08e479 | 34 | #:use-module (language cps cse) |
305cccb4 | 35 | #:use-module (language cps dce) |
6e8ad823 | 36 | #:use-module (language cps dfg) |
7e273b7a | 37 | #:use-module (language cps elide-values) |
6e8ad823 | 38 | #:use-module (language cps primitives) |
63463880 | 39 | #:use-module (language cps prune-bailouts) |
dd692618 | 40 | #:use-module (language cps prune-top-level-scopes) |
6e8ad823 | 41 | #:use-module (language cps reify-primitives) |
62b7180b | 42 | #:use-module (language cps renumber) |
c4a209b9 | 43 | #:use-module (language cps self-references) |
22a79b55 | 44 | #:use-module (language cps simplify) |
6e8ad823 | 45 | #:use-module (language cps slot-allocation) |
4c906ad5 | 46 | #:use-module (language cps specialize-primcalls) |
6e8ad823 | 47 | #:use-module (system vm assembler) |
691697de | 48 | #:export (compile-bytecode)) |
6e8ad823 | 49 | |
d258fccc | 50 | ;; TODO: Local var names. |
6e8ad823 AW |
51 | |
52 | (define (kw-arg-ref args kw default) | |
53 | (match (memq kw args) | |
54 | ((_ val . _) val) | |
55 | (_ default))) | |
56 | ||
57 | (define (optimize exp opts) | |
58 | (define (run-pass exp pass kw default) | |
59 | (if (kw-arg-ref opts kw default) | |
1d15832f | 60 | (pass exp) |
6e8ad823 AW |
61 | exp)) |
62 | ||
305cccb4 AW |
63 | ;; The first DCE pass is mainly to eliminate functions that aren't |
64 | ;; called. The last is mainly to eliminate rest parameters that | |
65 | ;; aren't used, and thus shouldn't be consed. | |
66 | ||
9e94cd9b | 67 | (let* ((exp (run-pass exp eliminate-dead-code #:eliminate-dead-code? #t)) |
dd692618 | 68 | (exp (run-pass exp prune-top-level-scopes #:prune-top-level-scopes? #t)) |
22a79b55 | 69 | (exp (run-pass exp simplify #:simplify? #t)) |
305cccb4 | 70 | (exp (run-pass exp contify #:contify? #t)) |
7e273b7a | 71 | (exp (run-pass exp inline-constructors #:inline-constructors? #t)) |
4c906ad5 | 72 | (exp (run-pass exp specialize-primcalls #:specialize-primcalls? #t)) |
305cccb4 | 73 | (exp (run-pass exp elide-values #:elide-values? #t)) |
9e94cd9b | 74 | (exp (run-pass exp prune-bailouts #:prune-bailouts? #t)) |
85270a8c | 75 | (exp (run-pass exp eliminate-common-subexpressions #:cse? #t)) |
c4a209b9 | 76 | (exp (run-pass exp resolve-self-references #:resolve-self-references? #t)) |
22a79b55 AW |
77 | (exp (run-pass exp eliminate-dead-code #:eliminate-dead-code? #t)) |
78 | (exp (run-pass exp simplify #:simplify? #t))) | |
6e8ad823 AW |
79 | ;; Passes that are needed: |
80 | ;; | |
6e8ad823 AW |
81 | ;; * Abort contification: turning abort primcalls into continuation |
82 | ;; calls, and eliding prompts if possible. | |
83 | ;; | |
6e8ad823 AW |
84 | ;; * Loop peeling. Unrolls the first round through a loop if the |
85 | ;; loop has effects that CSE can work on. Requires effects | |
86 | ;; analysis. When run before CSE, loop peeling is the equivalent | |
87 | ;; of loop-invariant code motion (LICM). | |
6e8ad823 AW |
88 | |
89 | exp)) | |
90 | ||
d258fccc | 91 | (define (compile-fun f asm) |
6bc36ca5 | 92 | (let* ((dfg (compute-dfg f #:global? #f)) |
a8430ab1 | 93 | (allocation (allocate-slots f dfg))) |
987c1f5f AW |
94 | (define (maybe-slot sym) |
95 | (lookup-maybe-slot sym allocation)) | |
96 | ||
6e422a35 AW |
97 | (define (slot sym) |
98 | (lookup-slot sym allocation)) | |
99 | ||
100 | (define (constant sym) | |
101 | (lookup-constant-value sym allocation)) | |
102 | ||
103 | (define (maybe-mov dst src) | |
104 | (unless (= dst src) | |
105 | (emit-mov asm dst src))) | |
106 | ||
107 | (define (maybe-load-constant slot src) | |
108 | (call-with-values (lambda () | |
109 | (lookup-maybe-constant-value src allocation)) | |
110 | (lambda (has-const? val) | |
111 | (and has-const? | |
112 | (begin | |
113 | (emit-load-constant asm slot val) | |
114 | #t))))) | |
115 | ||
24b611e8 | 116 | (define (compile-entry) |
a8430ab1 AW |
117 | (let ((label (dfg-min-label dfg))) |
118 | (match (lookup-cont label dfg) | |
8320f504 | 119 | (($ $kfun src meta self tail clause) |
24b611e8 AW |
120 | (when src |
121 | (emit-source asm src)) | |
a8430ab1 AW |
122 | (emit-begin-program asm label meta) |
123 | (compile-clause (1+ label)) | |
124 | (emit-end-program asm))))) | |
90dce16d | 125 | |
a8430ab1 AW |
126 | (define (compile-clause label) |
127 | (match (lookup-cont label dfg) | |
90dce16d AW |
128 | (($ $kclause ($ $arity req opt rest kw allow-other-keys?) |
129 | body alternate) | |
6e422a35 AW |
130 | (let* ((kw-indices (map (match-lambda |
131 | ((key name sym) | |
132 | (cons key (lookup-slot sym allocation)))) | |
133 | kw)) | |
a8430ab1 AW |
134 | (nlocals (lookup-nlocals label allocation))) |
135 | (emit-label asm label) | |
90dce16d AW |
136 | (emit-begin-kw-arity asm req opt rest kw-indices allow-other-keys? |
137 | nlocals | |
138 | (match alternate (#f #f) (($ $cont alt) alt))) | |
a8430ab1 | 139 | (let ((next (compile-body (1+ label) nlocals))) |
6e422a35 | 140 | (emit-end-arity asm) |
90dce16d AW |
141 | (match alternate |
142 | (($ $cont alt) | |
a8430ab1 | 143 | (unless (eq? next alt) |
90dce16d AW |
144 | (error "unexpected k" alt)) |
145 | (compile-clause next)) | |
146 | (#f | |
a8430ab1 | 147 | (unless (= next (+ (dfg-min-label dfg) (dfg-label-count dfg))) |
90dce16d | 148 | (error "unexpected end of clauses"))))))))) |
6e422a35 | 149 | |
a8430ab1 AW |
150 | (define (compile-body label nlocals) |
151 | (let compile-cont ((label label)) | |
152 | (if (eq? label (+ (dfg-min-label dfg) (dfg-label-count dfg))) | |
153 | label | |
154 | (match (lookup-cont label dfg) | |
155 | (($ $kclause) label) | |
6e422a35 | 156 | (($ $kargs _ _ term) |
a8430ab1 | 157 | (emit-label asm label) |
6e422a35 AW |
158 | (let find-exp ((term term)) |
159 | (match term | |
160 | (($ $letk conts term) | |
161 | (find-exp term)) | |
162 | (($ $continue k src exp) | |
163 | (when src | |
164 | (emit-source asm src)) | |
a8430ab1 AW |
165 | (compile-expression label k exp nlocals) |
166 | (compile-cont (1+ label)))))) | |
6e422a35 | 167 | (_ |
a8430ab1 AW |
168 | (emit-label asm label) |
169 | (compile-cont (1+ label))))))) | |
6e422a35 | 170 | |
a8430ab1 AW |
171 | (define (compile-expression label k exp nlocals) |
172 | (let* ((fallthrough? (= k (1+ label)))) | |
6e422a35 | 173 | (define (maybe-emit-jump) |
a8430ab1 | 174 | (unless fallthrough? |
6e422a35 | 175 | (emit-br asm k))) |
a8430ab1 | 176 | (match (lookup-cont k dfg) |
6e422a35 AW |
177 | (($ $ktail) |
178 | (compile-tail label exp)) | |
179 | (($ $kargs (name) (sym)) | |
987c1f5f | 180 | (let ((dst (maybe-slot sym))) |
6e422a35 AW |
181 | (when dst |
182 | (compile-value label exp dst nlocals))) | |
183 | (maybe-emit-jump)) | |
184 | (($ $kargs () ()) | |
185 | (compile-effect label exp k nlocals) | |
186 | (maybe-emit-jump)) | |
187 | (($ $kargs names syms) | |
188 | (compile-values label exp syms) | |
189 | (maybe-emit-jump)) | |
190 | (($ $kif kt kf) | |
a8430ab1 | 191 | (compile-test label exp kt kf (and fallthrough? (1+ k)))) |
36527695 | 192 | (($ $kreceive ($ $arity req () rest () #f) kargs) |
fa48a2f7 AW |
193 | (compile-trunc label k exp (length req) |
194 | (and rest | |
a8430ab1 | 195 | (match (lookup-cont kargs dfg) |
fa48a2f7 AW |
196 | (($ $kargs names (_ ... rest)) rest))) |
197 | nlocals) | |
a8430ab1 | 198 | (unless (and fallthrough? (= kargs (1+ k))) |
987c1f5f | 199 | (emit-br asm kargs)))))) |
6e422a35 AW |
200 | |
201 | (define (compile-tail label exp) | |
202 | ;; There are only three kinds of expressions in tail position: | |
203 | ;; tail calls, multiple-value returns, and single-value returns. | |
204 | (match exp | |
205 | (($ $call proc args) | |
206 | (for-each (match-lambda | |
207 | ((src . dst) (emit-mov asm dst src))) | |
208 | (lookup-parallel-moves label allocation)) | |
209 | (let ((tail-slots (cdr (iota (1+ (length args)))))) | |
210 | (for-each maybe-load-constant tail-slots args)) | |
211 | (emit-tail-call asm (1+ (length args)))) | |
b3ae2b50 AW |
212 | (($ $callk k proc args) |
213 | (for-each (match-lambda | |
214 | ((src . dst) (emit-mov asm dst src))) | |
215 | (lookup-parallel-moves label allocation)) | |
216 | (let ((tail-slots (cdr (iota (1+ (length args)))))) | |
217 | (for-each maybe-load-constant tail-slots args)) | |
218 | (emit-tail-call-label asm (1+ (length args)) k)) | |
987c1f5f AW |
219 | (($ $values ()) |
220 | (emit-reset-frame asm 1) | |
221 | (emit-return-values asm)) | |
13085a82 | 222 | (($ $values (arg)) |
987c1f5f | 223 | (if (maybe-slot arg) |
13085a82 AW |
224 | (emit-return asm (slot arg)) |
225 | (begin | |
226 | (emit-load-constant asm 1 (constant arg)) | |
227 | (emit-return asm 1)))) | |
6e422a35 | 228 | (($ $values args) |
13085a82 AW |
229 | (for-each (match-lambda |
230 | ((src . dst) (emit-mov asm dst src))) | |
231 | (lookup-parallel-moves label allocation)) | |
6e422a35 | 232 | (let ((tail-slots (cdr (iota (1+ (length args)))))) |
6e422a35 AW |
233 | (for-each maybe-load-constant tail-slots args)) |
234 | (emit-reset-frame asm (1+ (length args))) | |
235 | (emit-return-values asm)) | |
236 | (($ $primcall 'return (arg)) | |
237 | (emit-return asm (slot arg))))) | |
238 | ||
239 | (define (compile-value label exp dst nlocals) | |
240 | (match exp | |
6e422a35 AW |
241 | (($ $values (arg)) |
242 | (or (maybe-load-constant dst arg) | |
243 | (maybe-mov dst (slot arg)))) | |
244 | (($ $void) | |
245 | (emit-load-constant asm dst *unspecified*)) | |
246 | (($ $const exp) | |
247 | (emit-load-constant asm dst exp)) | |
24b611e8 | 248 | (($ $fun () ($ $cont k)) |
6e422a35 | 249 | (emit-load-static-procedure asm dst k)) |
24b611e8 | 250 | (($ $fun free ($ $cont k)) |
6e422a35 | 251 | (emit-make-closure asm dst k (length free))) |
6e422a35 AW |
252 | (($ $primcall 'current-module) |
253 | (emit-current-module asm dst)) | |
254 | (($ $primcall 'cached-toplevel-box (scope name bound?)) | |
255 | (emit-cached-toplevel-box asm dst (constant scope) (constant name) | |
256 | (constant bound?))) | |
257 | (($ $primcall 'cached-module-box (mod name public? bound?)) | |
258 | (emit-cached-module-box asm dst (constant mod) (constant name) | |
259 | (constant public?) (constant bound?))) | |
260 | (($ $primcall 'resolve (name bound?)) | |
261 | (emit-resolve asm dst (constant bound?) (slot name))) | |
262 | (($ $primcall 'free-ref (closure idx)) | |
263 | (emit-free-ref asm dst (slot closure) (constant idx))) | |
6e422a35 | 264 | (($ $primcall 'vector-ref (vector index)) |
4c906ad5 AW |
265 | (emit-vector-ref asm dst (slot vector) (slot index))) |
266 | (($ $primcall 'make-vector/immediate (length init)) | |
267 | (emit-make-vector/immediate asm dst (constant length) (slot init))) | |
268 | (($ $primcall 'vector-ref/immediate (vector index)) | |
269 | (emit-vector-ref/immediate asm dst (slot vector) (constant index))) | |
270 | (($ $primcall 'allocate-struct/immediate (vtable nfields)) | |
271 | (emit-allocate-struct/immediate asm dst (slot vtable) (constant nfields))) | |
272 | (($ $primcall 'struct-ref/immediate (struct n)) | |
273 | (emit-struct-ref/immediate asm dst (slot struct) (constant n))) | |
6e422a35 AW |
274 | (($ $primcall 'builtin-ref (name)) |
275 | (emit-builtin-ref asm dst (constant name))) | |
276 | (($ $primcall 'bv-u8-ref (bv idx)) | |
277 | (emit-bv-u8-ref asm dst (slot bv) (slot idx))) | |
d59060ce AW |
278 | (($ $primcall 'bv-s8-ref (bv idx)) |
279 | (emit-bv-s8-ref asm dst (slot bv) (slot idx))) | |
6e422a35 AW |
280 | (($ $primcall 'bv-u16-ref (bv idx)) |
281 | (emit-bv-u16-ref asm dst (slot bv) (slot idx))) | |
282 | (($ $primcall 'bv-s16-ref (bv idx)) | |
283 | (emit-bv-s16-ref asm dst (slot bv) (slot idx))) | |
284 | (($ $primcall 'bv-u32-ref (bv idx val)) | |
285 | (emit-bv-u32-ref asm dst (slot bv) (slot idx))) | |
286 | (($ $primcall 'bv-s32-ref (bv idx val)) | |
287 | (emit-bv-s32-ref asm dst (slot bv) (slot idx))) | |
288 | (($ $primcall 'bv-u64-ref (bv idx val)) | |
289 | (emit-bv-u64-ref asm dst (slot bv) (slot idx))) | |
290 | (($ $primcall 'bv-s64-ref (bv idx val)) | |
291 | (emit-bv-s64-ref asm dst (slot bv) (slot idx))) | |
292 | (($ $primcall 'bv-f32-ref (bv idx val)) | |
293 | (emit-bv-f32-ref asm dst (slot bv) (slot idx))) | |
294 | (($ $primcall 'bv-f64-ref (bv idx val)) | |
295 | (emit-bv-f64-ref asm dst (slot bv) (slot idx))) | |
296 | (($ $primcall name args) | |
297 | ;; FIXME: Inline all the cases. | |
691697de | 298 | (let ((inst (prim-instruction name))) |
6e422a35 AW |
299 | (emit-text asm `((,inst ,dst ,@(map slot args)))))))) |
300 | ||
301 | (define (compile-effect label exp k nlocals) | |
302 | (match exp | |
303 | (($ $values ()) #f) | |
7ab76a83 | 304 | (($ $prompt escape? tag handler) |
a8430ab1 | 305 | (match (lookup-cont handler dfg) |
36527695 | 306 | (($ $kreceive ($ $arity req () rest () #f) khandler-body) |
6e422a35 AW |
307 | (let ((receive-args (gensym "handler")) |
308 | (nreq (length req)) | |
987c1f5f | 309 | (proc-slot (lookup-call-proc-slot handler allocation))) |
6e422a35 AW |
310 | (emit-prompt asm (slot tag) escape? proc-slot receive-args) |
311 | (emit-br asm k) | |
312 | (emit-label asm receive-args) | |
4dfcb360 AW |
313 | (unless (and rest (zero? nreq)) |
314 | (emit-receive-values asm proc-slot (->bool rest) nreq)) | |
fa48a2f7 | 315 | (when (and rest |
a8430ab1 | 316 | (match (lookup-cont khandler-body dfg) |
fa48a2f7 AW |
317 | (($ $kargs names (_ ... rest)) |
318 | (maybe-slot rest)))) | |
6e422a35 AW |
319 | (emit-bind-rest asm (+ proc-slot 1 nreq))) |
320 | (for-each (match-lambda | |
321 | ((src . dst) (emit-mov asm dst src))) | |
322 | (lookup-parallel-moves handler allocation)) | |
323 | (emit-reset-frame asm nlocals) | |
324 | (emit-br asm khandler-body))))) | |
325 | (($ $primcall 'cache-current-module! (sym scope)) | |
326 | (emit-cache-current-module! asm (slot sym) (constant scope))) | |
327 | (($ $primcall 'free-set! (closure idx value)) | |
328 | (emit-free-set! asm (slot closure) (slot value) (constant idx))) | |
329 | (($ $primcall 'box-set! (box value)) | |
330 | (emit-box-set! asm (slot box) (slot value))) | |
4c906ad5 AW |
331 | (($ $primcall 'struct-set!/immediate (struct index value)) |
332 | (emit-struct-set!/immediate asm (slot struct) (constant index) (slot value))) | |
6e422a35 | 333 | (($ $primcall 'vector-set! (vector index value)) |
4c906ad5 AW |
334 | (emit-vector-set! asm (slot vector) (slot index) (slot value))) |
335 | (($ $primcall 'vector-set!/immediate (vector index value)) | |
336 | (emit-vector-set!/immediate asm (slot vector) (constant index) | |
337 | (slot value))) | |
6e422a35 AW |
338 | (($ $primcall 'set-car! (pair value)) |
339 | (emit-set-car! asm (slot pair) (slot value))) | |
340 | (($ $primcall 'set-cdr! (pair value)) | |
341 | (emit-set-cdr! asm (slot pair) (slot value))) | |
342 | (($ $primcall 'define! (sym value)) | |
343 | (emit-define! asm (slot sym) (slot value))) | |
344 | (($ $primcall 'push-fluid (fluid val)) | |
345 | (emit-push-fluid asm (slot fluid) (slot val))) | |
346 | (($ $primcall 'pop-fluid ()) | |
347 | (emit-pop-fluid asm)) | |
348 | (($ $primcall 'wind (winder unwinder)) | |
349 | (emit-wind asm (slot winder) (slot unwinder))) | |
350 | (($ $primcall 'bv-u8-set! (bv idx val)) | |
351 | (emit-bv-u8-set! asm (slot bv) (slot idx) (slot val))) | |
d59060ce AW |
352 | (($ $primcall 'bv-s8-set! (bv idx val)) |
353 | (emit-bv-s8-set! asm (slot bv) (slot idx) (slot val))) | |
6e422a35 AW |
354 | (($ $primcall 'bv-u16-set! (bv idx val)) |
355 | (emit-bv-u16-set! asm (slot bv) (slot idx) (slot val))) | |
356 | (($ $primcall 'bv-s16-set! (bv idx val)) | |
357 | (emit-bv-s16-set! asm (slot bv) (slot idx) (slot val))) | |
358 | (($ $primcall 'bv-u32-set! (bv idx val)) | |
359 | (emit-bv-u32-set! asm (slot bv) (slot idx) (slot val))) | |
360 | (($ $primcall 'bv-s32-set! (bv idx val)) | |
361 | (emit-bv-s32-set! asm (slot bv) (slot idx) (slot val))) | |
362 | (($ $primcall 'bv-u64-set! (bv idx val)) | |
363 | (emit-bv-u64-set! asm (slot bv) (slot idx) (slot val))) | |
364 | (($ $primcall 'bv-s64-set! (bv idx val)) | |
365 | (emit-bv-s64-set! asm (slot bv) (slot idx) (slot val))) | |
366 | (($ $primcall 'bv-f32-set! (bv idx val)) | |
367 | (emit-bv-f32-set! asm (slot bv) (slot idx) (slot val))) | |
368 | (($ $primcall 'bv-f64-set! (bv idx val)) | |
369 | (emit-bv-f64-set! asm (slot bv) (slot idx) (slot val))) | |
370 | (($ $primcall 'unwind ()) | |
371 | (emit-unwind asm)))) | |
372 | ||
373 | (define (compile-values label exp syms) | |
374 | (match exp | |
375 | (($ $values args) | |
376 | (for-each (match-lambda | |
377 | ((src . dst) (emit-mov asm dst src))) | |
378 | (lookup-parallel-moves label allocation)) | |
379 | (for-each maybe-load-constant (map slot syms) args)))) | |
380 | ||
381 | (define (compile-test label exp kt kf next-label) | |
382 | (define (unary op sym) | |
383 | (cond | |
384 | ((eq? kt next-label) | |
385 | (op asm (slot sym) #t kf)) | |
386 | (else | |
387 | (op asm (slot sym) #f kt) | |
388 | (unless (eq? kf next-label) | |
389 | (emit-br asm kf))))) | |
390 | (define (binary op a b) | |
391 | (cond | |
392 | ((eq? kt next-label) | |
393 | (op asm (slot a) (slot b) #t kf)) | |
394 | (else | |
395 | (op asm (slot a) (slot b) #f kt) | |
396 | (unless (eq? kf next-label) | |
397 | (emit-br asm kf))))) | |
398 | (match exp | |
58ef5f07 AW |
399 | (($ $values (sym)) |
400 | (call-with-values (lambda () | |
401 | (lookup-maybe-constant-value sym allocation)) | |
402 | (lambda (has-const? val) | |
403 | (if has-const? | |
404 | (if val | |
405 | (unless (eq? kt next-label) | |
406 | (emit-br asm kt)) | |
407 | (unless (eq? kf next-label) | |
408 | (emit-br asm kf))) | |
409 | (unary emit-br-if-true sym))))) | |
6e422a35 AW |
410 | (($ $primcall 'null? (a)) (unary emit-br-if-null a)) |
411 | (($ $primcall 'nil? (a)) (unary emit-br-if-nil a)) | |
412 | (($ $primcall 'pair? (a)) (unary emit-br-if-pair a)) | |
413 | (($ $primcall 'struct? (a)) (unary emit-br-if-struct a)) | |
414 | (($ $primcall 'char? (a)) (unary emit-br-if-char a)) | |
415 | (($ $primcall 'symbol? (a)) (unary emit-br-if-symbol a)) | |
416 | (($ $primcall 'variable? (a)) (unary emit-br-if-variable a)) | |
417 | (($ $primcall 'vector? (a)) (unary emit-br-if-vector a)) | |
418 | (($ $primcall 'string? (a)) (unary emit-br-if-string a)) | |
419 | (($ $primcall 'bytevector? (a)) (unary emit-br-if-bytevector a)) | |
420 | ;; Add more TC7 tests here. Keep in sync with | |
421 | ;; *branching-primcall-arities* in (language cps primitives) and | |
422 | ;; the set of macro-instructions in assembly.scm. | |
423 | (($ $primcall 'eq? (a b)) (binary emit-br-if-eq a b)) | |
424 | (($ $primcall 'eqv? (a b)) (binary emit-br-if-eqv a b)) | |
425 | (($ $primcall 'equal? (a b)) (binary emit-br-if-equal a b)) | |
426 | (($ $primcall '< (a b)) (binary emit-br-if-< a b)) | |
427 | (($ $primcall '<= (a b)) (binary emit-br-if-<= a b)) | |
428 | (($ $primcall '= (a b)) (binary emit-br-if-= a b)) | |
429 | (($ $primcall '>= (a b)) (binary emit-br-if-<= b a)) | |
430 | (($ $primcall '> (a b)) (binary emit-br-if-< b a)))) | |
431 | ||
fa48a2f7 | 432 | (define (compile-trunc label k exp nreq rest-var nlocals) |
b3ae2b50 AW |
433 | (define (do-call proc args emit-call) |
434 | (let* ((proc-slot (lookup-call-proc-slot label allocation)) | |
435 | (nargs (1+ (length args))) | |
436 | (arg-slots (map (lambda (x) (+ x proc-slot)) (iota nargs)))) | |
437 | (for-each (match-lambda | |
438 | ((src . dst) (emit-mov asm dst src))) | |
439 | (lookup-parallel-moves label allocation)) | |
440 | (for-each maybe-load-constant arg-slots (cons proc args)) | |
441 | (emit-call asm proc-slot nargs) | |
442 | (emit-dead-slot-map asm proc-slot | |
443 | (lookup-dead-slot-map label allocation)) | |
444 | (cond | |
445 | ((and (= 1 nreq) (and rest-var) (not (maybe-slot rest-var)) | |
446 | (match (lookup-parallel-moves k allocation) | |
447 | ((((? (lambda (src) (= src (1+ proc-slot))) src) | |
448 | . dst)) dst) | |
449 | (_ #f))) | |
450 | ;; The usual case: one required live return value, ignoring | |
451 | ;; any additional values. | |
452 | => (lambda (dst) | |
453 | (emit-receive asm dst proc-slot nlocals))) | |
454 | (else | |
455 | (unless (and (zero? nreq) rest-var) | |
456 | (emit-receive-values asm proc-slot (->bool rest-var) nreq)) | |
457 | (when (and rest-var (maybe-slot rest-var)) | |
458 | (emit-bind-rest asm (+ proc-slot 1 nreq))) | |
459 | (for-each (match-lambda | |
460 | ((src . dst) (emit-mov asm dst src))) | |
461 | (lookup-parallel-moves k allocation)) | |
462 | (emit-reset-frame asm nlocals))))) | |
6e422a35 AW |
463 | (match exp |
464 | (($ $call proc args) | |
b3ae2b50 AW |
465 | (do-call proc args |
466 | (lambda (asm proc-slot nargs) | |
467 | (emit-call asm proc-slot nargs)))) | |
468 | (($ $callk k proc args) | |
469 | (do-call proc args | |
470 | (lambda (asm proc-slot nargs) | |
471 | (emit-call-label asm proc-slot nargs k)))))) | |
6e422a35 AW |
472 | |
473 | (match f | |
6bc36ca5 | 474 | (($ $cont k ($ $kfun src meta self tail clause)) |
24b611e8 | 475 | (compile-entry))))) |
d258fccc | 476 | |
6e8ad823 AW |
477 | (define (visit-funs proc exp) |
478 | (match exp | |
6e422a35 | 479 | (($ $continue _ _ exp) |
6e8ad823 AW |
480 | (visit-funs proc exp)) |
481 | ||
24b611e8 | 482 | (($ $fun free body) |
6e8ad823 AW |
483 | (visit-funs proc body)) |
484 | ||
485 | (($ $letk conts body) | |
486 | (visit-funs proc body) | |
487 | (for-each (lambda (cont) (visit-funs proc cont)) conts)) | |
488 | ||
6e422a35 | 489 | (($ $cont sym ($ $kargs names syms body)) |
6e8ad823 AW |
490 | (visit-funs proc body)) |
491 | ||
90dce16d AW |
492 | (($ $cont sym ($ $kclause arity body alternate)) |
493 | (visit-funs proc body) | |
494 | (when alternate | |
495 | (visit-funs proc alternate))) | |
6e8ad823 | 496 | |
8320f504 | 497 | (($ $cont sym ($ $kfun src meta self tail clause)) |
6bc36ca5 | 498 | (proc exp) |
90dce16d AW |
499 | (when clause |
500 | (visit-funs proc clause))) | |
6e8ad823 AW |
501 | |
502 | (_ (values)))) | |
503 | ||
691697de | 504 | (define (compile-bytecode exp env opts) |
6e8ad823 AW |
505 | (let* ((exp (fix-arities exp)) |
506 | (exp (optimize exp opts)) | |
507 | (exp (convert-closures exp)) | |
508 | (exp (reify-primitives exp)) | |
b85f5f85 AW |
509 | (exp (match (renumber (build-cps-exp ($fun '() ,exp))) |
510 | (($ $fun free body) body))) | |
6e8ad823 AW |
511 | (asm (make-assembler))) |
512 | (visit-funs (lambda (fun) | |
513 | (compile-fun fun asm)) | |
b85f5f85 | 514 | exp) |
6e8ad823 AW |
515 | (values (link-assembly asm #:page-aligned? (kw-arg-ref opts #:to-file? #f)) |
516 | env | |
517 | env))) |