~ chicken-core (chicken-5) /support.scm
Trap1;;;; support.scm - Miscellaneous support code for the CHICKEN compiler
2;
3; Copyright (c) 2008-2022, The CHICKEN Team
4; Copyright (c) 2000-2007, Felix L. Winkelmann
5; All rights reserved.
6;
7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
8; conditions are met:
9;
10; Redistributions of source code must retain the above copyright notice, this list of conditions and the following
11; disclaimer.
12; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
13; disclaimer in the documentation and/or other materials provided with the distribution.
14; Neither the name of the author nor the names of its contributors may be used to endorse or promote
15; products derived from this software without specific prior written permission.
16;
17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25; POSSIBILITY OF SUCH DAMAGE.
26
27
28(declare (unit support)
29 (not inline ##sys#user-read-hook) ; XXX: Is this needed?
30 (uses data-structures extras file internal pathname port))
31
32(module chicken.compiler.support
33 (compiler-cleanup-hook bomb collected-debugging-output debugging
34 debugging-chicken with-debugging-output quit-compiling
35 emit-syntax-trace-info check-signature build-lambda-list
36 c-ify-string valid-c-identifier? read-expressions
37 bytes->words words->bytes replace-rest-op-with-list-ops
38 check-and-open-input-file close-checked-input-file fold-inner
39 constant? collapsable-literal? immediate? basic-literal?
40 canonicalize-begin-body string->expr llist-length llist-match?
41 expand-profile-lambda reset-profile-info-vector-name!
42 profiling-prelude-exps db-get db-get-all db-put! collect! db-get-list
43 make-node node? node-class node-class-set! node-parameters node-parameters-set!
44 node-subexpressions node-subexpressions-set! varnode qnode
45 build-node-graph build-expression-tree fold-boolean inline-lambda-bindings
46 tree-copy copy-node! copy-node emit-global-inline-file load-inline-file
47 match-node expression-has-side-effects? simple-lambda-node?
48 dump-undefined-globals dump-defined-globals dump-global-refs
49 make-foreign-callback-stub foreign-callback-stub?
50 foreign-callback-stub-id foreign-callback-stub-name
51 foreign-callback-stub-qualifiers foreign-callback-stub-return-type
52 foreign-callback-stub-argument-types register-foreign-callback-stub!
53 foreign-callback-stubs ; should not be exported
54 foreign-type-check foreign-type-convert-result
55 foreign-type-convert-argument final-foreign-type
56 register-foreign-type! lookup-foreign-type clear-foreign-type-table!
57 estimate-foreign-result-size estimate-foreign-result-location-size
58 finish-foreign-result foreign-type->scrutiny-type scan-used-variables
59 scan-free-variables
60 make-block-variable-literal block-variable-literal?
61 block-variable-literal-name make-random-name
62 clear-real-name-table! get-real-name set-real-name!
63 real-name real-name2 display-real-name-table
64 source-info->string source-info->line source-info->name
65 call-info constant-form-eval maybe-constant-fold-call
66 dump-nodes read/source-info big-fixnum? small-bignum?
67 hide-variable export-variable variable-hidden? variable-visible?
68 mark-variable variable-mark intrinsic? predicate? foldable?
69 load-identifier-database
70 print-version print-usage print-debug-options
71
72 ;; XXX: These are evil globals that were too hairy to get rid of.
73 ;; These values are set! by compiler and batch-driver, and read
74 ;; in a lot of other places.
75 number-type unsafe)
76
77(import scheme
78 chicken.base
79 chicken.bitwise
80 chicken.blob
81 chicken.condition
82 chicken.file
83 chicken.fixnum
84 chicken.foreign
85 chicken.format
86 chicken.internal
87 chicken.io
88 chicken.keyword
89 chicken.pathname
90 chicken.platform
91 chicken.plist
92 chicken.port
93 chicken.pretty-print
94 chicken.sort
95 chicken.string
96 chicken.syntax
97 chicken.time)
98
99(include "tweaks")
100(include "mini-srfi-1.scm")
101(include "banner")
102
103;; Evil globals
104(define number-type 'generic)
105(define unsafe #f)
106
107;;; Debugging and error-handling stuff:
108
109(define (compiler-cleanup-hook) #f)
110
111(define debugging-chicken '())
112
113(define (bomb . msg-and-args)
114 (if (pair? msg-and-args)
115 (apply error (string-append "[internal compiler error] " (car msg-and-args)) (cdr msg-and-args))
116 (error "[internal compiler error]") ) )
117
118(define collected-debugging-output
119 (open-output-string))
120
121(define +logged-debugging-modes+ '(o x S))
122
123(define (test-debugging-mode mode enabled)
124 (if (symbol? mode)
125 (memq mode enabled)
126 (any (lambda (m) (memq m enabled)) mode)))
127
128(define (debugging mode msg . args)
129 (define (text)
130 (with-output-to-string
131 (lambda ()
132 (display msg)
133 (when (pair? args)
134 (display ": ")
135 (for-each
136 (lambda (x) (printf "~s " (force x)))
137 args) )
138 (newline))))
139 (define (dump txt)
140 (fprintf collected-debugging-output "~a|~a" mode txt))
141 (cond ((test-debugging-mode mode debugging-chicken)
142 (let ((txt (text)))
143 (display txt)
144 (flush-output)
145 (when (test-debugging-mode mode +logged-debugging-modes+)
146 (dump txt))
147 #t))
148 (else
149 (when (test-debugging-mode mode +logged-debugging-modes+)
150 (dump (text)))
151 #f)))
152
153(define (with-debugging-output mode thunk)
154 (define (collect text)
155 (for-each
156 (lambda (ln)
157 (fprintf collected-debugging-output "~a|~a~%"
158 (if (pair? mode) (car mode) mode)
159 ln))
160 (string-split text "\n")))
161 (cond ((test-debugging-mode mode debugging-chicken)
162 (let ((txt (with-output-to-string thunk)))
163 (display txt)
164 (flush-output)
165 (when (test-debugging-mode mode +logged-debugging-modes+)
166 (collect txt))))
167 ((test-debugging-mode mode +logged-debugging-modes+)
168 (collect (with-output-to-string thunk)))))
169
170(define (quit-compiling msg . args)
171 (let ([out (current-error-port)])
172 (apply fprintf out (string-append "\nError: " msg) args)
173 (newline out)
174 (exit 1) ) )
175
176(set! ##sys#syntax-error-hook
177 (lambda (msg . args)
178 (let ((out (current-error-port))
179 (loc (and (symbol? msg)
180 (let ((loc msg))
181 (set! msg (car args))
182 (set! args (cdr args))
183 loc))))
184 (if loc
185 (fprintf out "\nSyntax error (~a): ~a~%~%" loc msg)
186 (fprintf out "\nSyntax error: ~a~%~%" msg) )
187 (for-each (cut fprintf out "\t~s~%" <>) args)
188 (print-call-chain out 0 ##sys#current-thread "\n\tExpansion history:\n")
189 (exit 70) ) ) )
190
191(set! syntax-error ##sys#syntax-error-hook)
192
193(define (emit-syntax-trace-info info cntr)
194 (define (thread-id t) (##sys#slot t 14))
195 (##core#inline "C_emit_syntax_trace_info" info cntr
196 (thread-id ##sys#current-thread)))
197
198(define (map-llist proc llist)
199 (let loop ([llist llist])
200 (cond [(null? llist) '()]
201 [(symbol? llist) (proc llist)]
202 [else (cons (proc (car llist)) (loop (cdr llist)))] ) ) )
203
204(define (check-signature var args llist)
205 (let loop ((as args) (ll llist))
206 (cond ((null? ll) (null? as))
207 ((symbol? ll))
208 ((null? as) #f)
209 (else (loop (cdr as) (cdr ll))) ) ) )
210
211
212;;; Generic utility routines:
213
214(define (build-lambda-list vars argc rest)
215 (let loop ((vars vars) (n argc))
216 (cond ((or (zero? n) (null? vars)) (or rest '()))
217 (else (cons (car vars) (loop (cdr vars) (sub1 n)))) ) ) )
218
219;; XXX: Put this too in c-platform or c-backend?
220(define (c-ify-string str)
221 (list->string
222 (cons
223 #\"
224 (let loop ((chars (string->list str)))
225 (if (null? chars)
226 '(#\")
227 (let* ((c (car chars))
228 (code (char->integer c)) )
229 (if (or (< code 32) (>= code 127) (memq c '(#\" #\' #\\ #\? #\*)))
230 (append '(#\\)
231 (cond ((< code 8) '(#\0 #\0))
232 ((< code 64) '(#\0))
233 (else '()) )
234 (string->list (number->string code 8))
235 (loop (cdr chars)) )
236 (cons c (loop (cdr chars))) ) ) ) ) ) ) )
237
238;; XXX: This too, but it's used only in core.scm, WTF?
239(define (valid-c-identifier? name)
240 (let ([str (string->list (->string name))])
241 (and (pair? str)
242 (let ([c0 (car str)])
243 (and (or (char-alphabetic? c0) (char=? #\_ c0))
244 (every (lambda (c) (or (char-alphabetic? c) (char-numeric? c) (char=? #\_ c)))
245 (cdr str)))))))
246
247;; TODO: Move these to (chicken memory)?
248(define bytes->words (foreign-lambda int "C_bytestowords" int))
249(define words->bytes (foreign-lambda int "C_wordstobytes" int))
250
251;; Used only in batch-driver; move it there?
252(define (check-and-open-input-file fname . line)
253 (cond ((string=? fname "-") (current-input-port))
254 ((file-exists? fname) (open-input-file fname))
255 ((or (null? line) (not (car line)))
256 (quit-compiling "Can not open file ~s" fname))
257 (else (quit-compiling "(~a) can not open file ~s" (car line) fname)) ) )
258
259(define (close-checked-input-file port fname)
260 (unless (string=? fname "-") (close-input-port port)) )
261
262(define (fold-inner proc lst)
263 (if (null? (cdr lst))
264 lst
265 (let fold ((xs (reverse lst)))
266 (apply
267 proc
268 (if (null? (cddr xs))
269 (list (cadr xs) (car xs))
270 (list (fold (cdr xs)) (car xs)) ) ) ) ) )
271
272(define (follow-without-loop seed proc abort)
273 (let loop ([x seed] [done '()])
274 (if (member x done)
275 (abort)
276 (proc x (lambda (x2) (loop x2 (cons x done)))) ) ) )
277
278(define (sort-symbols lst)
279 (sort lst (lambda (s1 s2) (string<? (symbol->string s1) (symbol->string s2)))))
280
281(define (read-expressions #!optional (port (current-input-port)))
282 (do ((x (read port) (read port))
283 (i 0 (add1 i))
284 (xs '() (cons x xs)))
285 ((eof-object? x) (reverse xs))))
286
287
288;;; Predicates on expressions and literals:
289
290;; TODO: Remove once we have a bootstrapping libchicken with bwp-object?
291(define (bwp-object? x) (##core#inline "C_bwpp" x))
292
293(define (constant? x)
294 (or (number? x)
295 (char? x)
296 (string? x)
297 (boolean? x)
298 (eof-object? x)
299 (bwp-object? x)
300 (blob? x)
301 (vector? x)
302 (##sys#srfi-4-vector? x)
303 (and (pair? x) (eq? 'quote (car x))) ) )
304
305(define (collapsable-literal? x)
306 (or (boolean? x)
307 (char? x)
308 (eof-object? x)
309 (bwp-object? x)
310 (number? x)
311 (symbol? x) ) )
312
313(define (immediate? x)
314 (or (and (fixnum? x) (not (big-fixnum? x))) ; 64-bit fixnums would result in platform-dependent .c files
315 (eq? (##core#undefined) x)
316 (null? x)
317 (eof-object? x)
318 (bwp-object? x)
319 (char? x)
320 (boolean? x) ) )
321
322(define (basic-literal? x)
323 (or (null? x)
324 (symbol? x)
325 (constant? x)
326 (and (vector? x) (every basic-literal? (vector->list x)))
327 (and (pair? x)
328 (basic-literal? (car x))
329 (basic-literal? (cdr x)) ) ) )
330
331
332;;; Expression manipulation:
333
334(define (canonicalize-begin-body body)
335 (let loop ((xs body))
336 (cond ((null? xs) '(##core#undefined))
337 ((null? (cdr xs)) (car xs))
338 ((let ([h (car xs)])
339 (or (equal? h '(##core#undefined))
340 (constant? h)
341 (equal? h '(##sys#void)) ) )
342 (loop (cdr xs)) )
343 (else `(let ((,(gensym 't) ,(car xs)))
344 ,(loop (cdr xs))) ) ) ) )
345
346;; Only used in batch-driver: move it there?
347(define string->expr
348 (let ([exn? (condition-predicate 'exn)]
349 [exn-msg (condition-property-accessor 'exn 'message)] )
350 (lambda (str)
351 (handle-exceptions ex
352 (quit-compiling "cannot parse expression: ~s [~a]~%"
353 str
354 (if (exn? ex)
355 (exn-msg ex)
356 (->string ex) ) )
357 (let ((xs (with-input-from-string
358 str
359 (lambda ()
360 (let loop ((lst '()))
361 (let ((x (read)))
362 (if (eof-object? x)
363 (reverse lst)
364 (loop (cons x lst)))))))))
365 (cond [(null? xs) '(##core#undefined)]
366 [(null? (cdr xs)) (car xs)]
367 [else `(begin ,@xs)] ) ) ) ) ) )
368
369;; Only used in optimizer; move it there? But it's a C function call, so
370;; it may be better in c-platform
371(define (llist-length llist)
372 (##core#inline "C_u_i_length" llist)) ; stops at non-pair node
373
374(define (llist-match? llist args) ; assumes #!optional/#!rest/#!key have been expanded
375 (let loop ((llist llist) (args args))
376 (cond ((null? llist) (null? args))
377 ((symbol? llist))
378 ((null? args) (atom? llist))
379 (else (loop (cdr llist) (cdr args))))))
380
381
382;;; Profiling instrumentation:
383(define profile-info-vector-name #f)
384(define (reset-profile-info-vector-name!)
385 (set! profile-info-vector-name (make-random-name 'profile-info)))
386
387(define profile-lambda-list '())
388(define profile-lambda-index 0)
389
390(define (expand-profile-lambda name llist body)
391 (let ([index profile-lambda-index]
392 [args (gensym)] )
393 (set! profile-lambda-list (alist-cons index name profile-lambda-list))
394 (set! profile-lambda-index (add1 index))
395 `(##core#lambda ,args
396 (##sys#dynamic-wind
397 (##core#lambda () (##sys#profile-entry ',index ,profile-info-vector-name))
398 (##core#lambda () (##sys#apply (##core#lambda ,llist ,body) ,args))
399 (##core#lambda () (##sys#profile-exit ',index ,profile-info-vector-name)) ) ) ) )
400
401;; Get expressions which initialize and populate the profiling vector
402(define (profiling-prelude-exps profile-name)
403 `((set! ,profile-info-vector-name
404 (##sys#register-profile-info
405 ',(length profile-lambda-list)
406 ',profile-name))
407 ,@(map (lambda (pl)
408 `(##sys#set-profile-info-vector!
409 ,profile-info-vector-name
410 ',(car pl)
411 ',(cdr pl) ) )
412 profile-lambda-list)))
413
414;;; Database operations:
415
416(define (db-get db key prop)
417 (let ((plist (hash-table-ref db key)))
418 (and plist
419 (let ([a (assq prop plist)])
420 (and a (##sys#slot a 1)) ) ) ) )
421
422(define (db-get-all db key . props)
423 (let ((plist (hash-table-ref db key)))
424 (if plist
425 (filter-map (lambda (prop) (assq prop plist)) props)
426 '() ) ) )
427
428(define (db-put! db key prop val)
429 (let ((plist (hash-table-ref db key)))
430 (if plist
431 (let ([a (assq prop plist)])
432 (cond [a (##sys#setslot a 1 val)]
433 [val (##sys#setslot plist 1 (alist-cons prop val (##sys#slot plist 1)))] ) )
434 (when val (hash-table-set! db key (list (cons prop val)))))))
435
436(define (collect! db key prop val)
437 (let ((plist (hash-table-ref db key)))
438 (if plist
439 (let ([a (assq prop plist)])
440 (cond [a (##sys#setslot a 1 (cons val (##sys#slot a 1)))]
441 [else (##sys#setslot plist 1 (alist-cons prop (list val) (##sys#slot plist 1)))] ) )
442 (hash-table-set! db key (list (list prop val))))))
443
444(define (db-get-list db key prop) ; returns '() if not set
445 (let ((x (db-get db key prop)))
446 (or x '())))
447
448
449;;; Node creation and -manipulation:
450
451;; Note: much of this stuff will be overridden by the inline-definitions in "tweaks.scm".
452
453(define-record-type node
454 (make-node class parameters subexpressions)
455 node?
456 (class node-class node-class-set!) ; symbol
457 (parameters node-parameters node-parameters-set!) ; (value...)
458 (subexpressions node-subexpressions node-subexpressions-set!)) ; (node...)
459
460(set-record-printer! node
461 (lambda (n out)
462 (fprintf out "#<node ~a ~a>" (node-class n) (node-parameters n))))
463
464(define (make-node c p s)
465 (##sys#make-structure 'chicken.compiler.support#node c p s))
466
467(define (varnode var) (make-node '##core#variable (list var) '()))
468(define (qnode const) (make-node 'quote (list const) '()))
469
470(define (build-node-graph exp)
471 (let ((count 0))
472 (define (walk x)
473 (cond ((symbol? x) (varnode x))
474 ((node? x) x)
475 ((not (pair? x)) (bomb "bad expression" x))
476 ((symbol? (car x))
477 (case (car x)
478 ((if ##core#undefined) (make-node (car x) '() (map walk (cdr x))))
479 ((quote)
480 (let ((c (cadr x)))
481 (qnode (if (and (number? c)
482 (eq? 'fixnum number-type)
483 (not (integer? c)) )
484 (begin
485 (warning
486 "literal is out of range - will be truncated to integer" c)
487 (inexact->exact (truncate c)) )
488 c) ) ) )
489 ((let)
490 (let ([bs (cadr x)]
491 [body (caddr x)] )
492 (if (null? bs)
493 (walk body)
494 (make-node
495 'let (unzip1 bs)
496 (append (map (lambda (b) (walk (cadr b))) (cadr x))
497 (list (walk body)) ) ) ) ) )
498 ((lambda ##core#lambda)
499 (make-node 'lambda (list (cadr x)) (list (walk (caddr x)))))
500 ((##core#the)
501 (make-node '##core#the
502 (list (second x) (third x))
503 (list (walk (fourth x)))))
504 ((##core#typecase)
505 ;; clause-head is already stripped
506 (let loop ((cls (cdddr x)) (types '()) (exps (list (walk (caddr x)))))
507 (cond ((null? cls) ; no "else" clause given
508 (make-node
509 '##core#typecase
510 (cons (cadr x) (reverse types))
511 (reverse
512 (cons (make-node '##core#undefined '() '()) exps))))
513 ((eq? 'else (caar cls))
514 (make-node
515 '##core#typecase
516 (cons (cadr x) (reverse (cons '* types)))
517 (reverse (cons (walk (cadar cls)) exps))))
518 (else (loop (cdr cls)
519 (cons (caar cls) types)
520 (cons (walk (cadar cls)) exps))))))
521 ((##core#primitive)
522 (let ((arg (cadr x)))
523 (make-node
524 (car x)
525 (list (if (and (pair? arg) (eq? 'quote (car arg))) (cadr arg) arg))
526 (map walk (cddr x)) ) ) )
527 ((##core#inline ##core#provide ##core#callunit)
528 (make-node (car x) (list (cadr x)) (map walk (cddr x))) )
529 ((##core#debug-event) ; 2nd argument is provided by canonicalization phase
530 (make-node (car x) (cdr x) '()))
531 ((##core#proc)
532 (make-node '##core#proc (list (cadr x) #t) '()) )
533 ((set! ##core#set!)
534 (make-node
535 'set! (list (cadr x))
536 (map walk (cddr x))))
537 ((##core#foreign-callback-wrapper)
538 (let ([name (cadr (second x))])
539 (make-node
540 '##core#foreign-callback-wrapper
541 (list name (cadr (third x)) (cadr (fourth x)) (cadr (fifth x)))
542 (list (walk (list-ref x 5))) ) ) )
543 ((##core#inline_allocate ##core#inline_ref ##core#inline_update
544 ##core#inline_loc_ref ##core#inline_loc_update)
545 (make-node (first x) (second x) (map walk (cddr x))) )
546 ((##core#app)
547 (make-node '##core#call (list #t) (map walk (cdr x))) )
548 (else
549 (receive (name ln) (##sys#get-line-2 x)
550 (make-node
551 '##core#call
552 (list (cond [(variable-mark name '##compiler#always-bound-to-procedure)
553 (set! count (add1 count))
554 #t]
555 [else #f] )
556 (if ln
557 (let ([rn (real-name name)])
558 (list ln
559 (or rn (##sys#symbol->string name))) )
560 (##sys#symbol->string name) ) )
561 (map walk x) ) ) ) ) )
562 (else (make-node '##core#call (list #f) (map walk x))) ) )
563 (let ([exp2 (walk exp)])
564 (when (positive? count)
565 (debugging 'o "eliminated procedure checks" count)) ;XXX perhaps throw this out
566 exp2) ) )
567
568(define (build-expression-tree node)
569 (let walk ((n node))
570 (let ((subs (node-subexpressions n))
571 (params (node-parameters n))
572 (class (node-class n)) )
573 (case class
574 ((if ##core#box ##core#cond) (cons class (map walk subs)))
575 ((##core#closure)
576 `(##core#closure ,params ,@(map walk subs)) )
577 ((##core#variable) (car params))
578 ((quote)
579 (let ((c (car params)))
580 (if (or (boolean? c) (string? c) (number? c) (char? c))
581 c
582 `(quote ,(car params)))))
583 ((let)
584 `(let ,(map list params (map walk (butlast subs)))
585 ,(walk (last subs)) ) )
586 ((##core#lambda)
587 (list (if (second params)
588 'lambda
589 '##core#lambda)
590 (third params)
591 (walk (car subs)) ) )
592 ((##core#the)
593 `(the ,(first params) ,(walk (first subs))))
594 ((##core#the/result)
595 (walk (first subs)))
596 ((##core#typecase)
597 `(compiler-typecase
598 ,(walk (first subs))
599 ,@(let loop ((types (cdr params)) (bodies (cdr subs)))
600 (if (null? types)
601 (if (null? bodies)
602 '()
603 `((else ,(walk (car bodies)))))
604 (cons (list (car types) (walk (car bodies)))
605 (loop (cdr types) (cdr bodies)))))))
606 ((##core#call)
607 (map walk subs))
608 ((##core#callunit) (cons* '##core#callunit (car params) (map walk subs)))
609 ((##core#undefined) (list class))
610 ((##core#bind)
611 (let loop ((n (car params)) (vals subs) (bindings '()))
612 (if (zero? n)
613 `(##core#bind ,(reverse bindings) ,(walk (car vals)))
614 (loop (- n 1) (cdr vals) (cons (walk (car vals)) bindings)) ) ) )
615 ((##core#unbox ##core#ref ##core#update ##core#update_i)
616 (cons* class (walk (car subs)) params (map walk (cdr subs))) )
617 ((##core#inline_allocate)
618 (cons* class params (map walk subs)))
619 (else (cons class (append params (map walk subs)))) ) ) ) )
620
621(define (fold-boolean proc lst)
622 (let fold ([vars lst])
623 (if (null? (cddr vars))
624 (apply proc vars)
625 (make-node
626 '##core#inline '("C_and")
627 (list (proc (first vars) (second vars))
628 (fold (cdr vars)) ) ) ) ) )
629
630;; Move to optimizer.scm?
631(define (inline-lambda-bindings llist args body copy? db cfk)
632 (##sys#decompose-lambda-list
633 llist
634 (lambda (vars argc rest)
635 (receive (largs rargs) (split-at args argc)
636 (let* ((rlist (if copy? (map gensym vars) vars))
637 (body (if copy?
638 (copy-node-tree-and-rename body vars rlist db cfk)
639 body) )
640 (rarg-aliases (map (lambda (r) (gensym 'rarg)) rargs)) )
641 (replace-rest-ops-in-known-call! db body rest (last rlist) rarg-aliases)
642
643 ;; Make sure rest ops aren't replaced after inlining (#1658)
644 ;; argvector does not belong to the same procedure anymore.
645 (when rest
646 (for-each (lambda (v)
647 (db-put! db v 'rest-cdr #f)
648 (db-put! db v 'rest-null? #f) )
649 (db-get-list db rest 'derived-rest-vars) )
650 (db-put! db rest 'rest-cdr #f)
651 (db-put! db rest 'derived-rest-vars '()) )
652
653 (let loop ((vars (take rlist argc))
654 (vals largs))
655 (if (null? vars)
656 (if rest
657 ;; NOTE: If contraction happens before rest-op
658 ;; detection, we might needlessly build a list.
659 (let loop2 ((rarg-values rargs)
660 (rarg-aliases rarg-aliases))
661 (if (null? rarg-aliases)
662 (if (null? (db-get-list db rest 'references))
663 body
664 (make-node
665 'let (list (last rlist))
666 (list (if (null? rargs)
667 (qnode '())
668 (make-node
669 '##core#inline_allocate
670 (list "C_a_i_list" (* 3 (length rargs)))
671 rargs) )
672 body) ))
673 (make-node 'let (list (car rarg-aliases))
674 (list (car rarg-values)
675 (loop2 (cdr rarg-values) (cdr rarg-aliases))))))
676 body)
677 (make-node 'let (list (car vars))
678 (list (car vals)
679 (loop (cdr vars) (cdr vals)))))))))))
680
681;; Copy along with the above
682(define (copy-node-tree-and-rename node vars aliases db cfk)
683 (let ((rlist (map cons vars aliases)))
684 (define (rename v rl) (alist-ref v rl eq? v))
685 (define (walk n rl)
686 (let ((subs (node-subexpressions n))
687 (params (node-parameters n))
688 (class (node-class n)) )
689 (case class
690 ((quote)
691 (make-node class params '()))
692 ((##core#variable)
693 (let ((var (first params)))
694 (when (db-get db var 'contractable)
695 (cfk var))
696 (varnode (rename var rl))) )
697 ((set!)
698 (make-node
699 'set! (list (rename (first params) rl))
700 (list (walk (first subs) rl)) ) )
701 ((let)
702 (let* ((v (first params))
703 (val1 (walk (first subs) rl))
704 (a (gensym v))
705 (rl2 (alist-cons v a rl)) )
706 (db-put! db a 'inline-transient #t)
707 (make-node
708 'let (list a)
709 (list val1 (walk (second subs) rl2)))) )
710 ((##core#lambda)
711 (##sys#decompose-lambda-list
712 (third params)
713 (lambda (vars argc rest)
714 (let* ((as (map (lambda (v)
715 (let ((a (gensym v)))
716 (db-put! db v 'inline-transient #t)
717 a))
718 vars) )
719 (rl2 (append (map cons vars as) rl)) )
720 (make-node
721 '##core#lambda
722 (list (gensym 'f) (second params) ; new function-id
723 (build-lambda-list as argc (and rest (rename rest rl2)))
724 (fourth params) )
725 (map (cut walk <> rl2) subs) ) ) ) ) )
726 (else (make-node class (tree-copy params)
727 (map (cut walk <> rl) subs))) ) ) )
728 (walk node rlist) ) )
729
730;; Replace rest-{car,cdr,null?} with equivalent code which accesses
731;; the rest argument directly.
732(define (replace-rest-ops-in-known-call! db node rest-var rest-alias rest-args)
733 (define (walk n)
734 (let ((subs (node-subexpressions n))
735 (params (node-parameters n))
736 (class (node-class n)) )
737 (case class
738 ((##core#rest-null?)
739 (if (eq? rest-var (first params))
740 (copy-node! (qnode (<= (length rest-args) (second params))) n)
741 n))
742 ((##core#rest-car)
743 (if (eq? rest-var (first params))
744 (let ((depth (second params))
745 (len (length rest-args)))
746 (if (> len depth)
747 (copy-node! (varnode (list-ref rest-args depth)) n)
748 (copy-node! (make-node '##core#inline
749 (list "C_rest_arg_out_of_bounds_error_value")
750 (list (qnode len) (qnode depth) (qnode 0)))
751 n)))
752 n))
753 ((##core#rest-cdr)
754 (cond ((eq? rest-var (first params))
755 (collect! db rest-var 'references n) ; Restore this reference
756 (let lp ((i (add1 (second params)))
757 (new-node (varnode rest-alias)))
758 (if (zero? i)
759 (copy-node! new-node n)
760 (lp (sub1 i)
761 (make-node '##core#inline (list "C_i_cdr") (list new-node))))))
762 (else n)))
763 (else (for-each walk subs)) ) ) )
764
765 (walk node) )
766
767(define (replace-rest-op-with-list-ops class rest-var-node params)
768 (case class
769 ((##core#rest-car)
770 (make-node '##core#inline
771 (list "C_i_list_ref")
772 (list rest-var-node (qnode (second params)))))
773 ((##core#rest-cdr)
774 (let lp ((cdr-calls (add1 (second params)))
775 (var rest-var-node))
776 (if (zero? cdr-calls)
777 var
778 (lp (sub1 cdr-calls)
779 (make-node '##core#inline (list "C_i_cdr") (list var))))))
780 ((##core#rest-null?)
781 (make-node '##core#inline
782 (list "C_i_greater_or_equalp")
783 (list (qnode (second params))
784 (make-node '##core#inline (list "C_i_length") (list rest-var-node)))))
785 ((##core#rest-length)
786 (make-node '##core#inline
787 (list "C_i_length")
788 (list rest-var-node (qnode (second params)))))
789 (else (bomb "Unknown rest op node class while undoing rest op for explicitly consed rest arg. This shouldn't happen!" class))))
790
791;; Maybe move to scrutinizer. It's generic enough to keep it here though
792(define (tree-copy t)
793 (let rec ([t t])
794 (if (pair? t)
795 (cons (rec (car t)) (rec (cdr t)))
796 t) ) )
797
798(define (copy-node n)
799 (make-node (node-class n)
800 (node-parameters n)
801 (node-subexpressions n)))
802
803(define (copy-node! from to)
804 (node-class-set! to (node-class from))
805 (node-parameters-set! to (node-parameters from))
806 (node-subexpressions-set! to (node-subexpressions from))
807 to)
808
809(define (node->sexpr n)
810 (let walk ((n n))
811 `(,(node-class n)
812 ,(node-parameters n)
813 ,@(map walk (node-subexpressions n)))))
814
815(define (sexpr->node x)
816 (let walk ((x x))
817 (make-node (car x) (cadr x) (map walk (cddr x)))))
818
819;; Only used in batch-driver.scm
820(define (emit-global-inline-file source-file inline-file db
821 block-compilation inline-limit
822 foreign-stubs)
823 (define (uses-foreign-stubs? node)
824 (let walk ((n node))
825 (case (node-class n)
826 ((##core#inline)
827 (memq (car (node-parameters n)) foreign-stubs))
828 (else
829 (any walk (node-subexpressions n))))))
830 (let ((lst '())
831 (out '()))
832 (hash-table-for-each
833 (lambda (sym plist)
834 (when (variable-visible? sym block-compilation)
835 (and-let* ((val (assq 'local-value plist))
836 ((not (node? (variable-mark sym '##compiler#inline-global))))
837 ((let ((val (assq 'value plist)))
838 (or (not val)
839 (not (eq? 'unknown (cdr val))))))
840 ((assq 'inlinable plist))
841 (lparams (node-parameters (cdr val)))
842 ((not (db-get db sym 'hidden-refs)))
843 ((case (variable-mark sym '##compiler#inline)
844 ((yes) #t)
845 ((no) #f)
846 (else
847 (< (fourth lparams) inline-limit))))
848 ;; See #1440
849 ((not (uses-foreign-stubs? (cdr val)))))
850 (set! lst (cons sym lst))
851 (set! out (cons (list sym (node->sexpr (cdr val))) out)))))
852 db)
853 (with-output-to-file inline-file
854 (lambda ()
855 (print "; GENERATED BY CHICKEN " (chicken-version) " FROM "
856 source-file "\n")
857 (for-each
858 (lambda (x)
859 (pp x)
860 (newline))
861 (reverse out))
862 (print "; END OF FILE")))
863 (when (and (pair? lst)
864 (debugging 'i "the following procedures can be globally inlined:"))
865 (for-each (cut print " " <>) (sort-symbols lst)))))
866
867;; Used only in batch-driver.scm
868(define (load-inline-file fname)
869 (with-input-from-file fname
870 (lambda ()
871 (let loop ()
872 (let ((x (read)))
873 (unless (eof-object? x)
874 (mark-variable
875 (car x)
876 '##compiler#inline-global
877 (sexpr->node (cadr x)))
878 (loop)))))))
879
880
881;;; Match node-structure with pattern:
882
883(define (match-node node pat vars) ; Only used in optimizer.scm
884 (let ((env '()))
885
886 (define (resolve v x)
887 (cond ((assq v env) => (lambda (a) (equal? x (cdr a))))
888 ((memq v vars)
889 (set! env (alist-cons v x env))
890 #t)
891 (else (eq? v x)) ) )
892
893 (define (match1 x p)
894 (cond ((not (pair? p)) (resolve p x))
895 ((not (pair? x)) #f)
896 ((match1 (car x) (car p)) (match1 (cdr x) (cdr p)))
897 (else #f) ) )
898
899 (define (matchn n p)
900 (if (not (pair? p))
901 (resolve p n)
902 (and (eq? (node-class n) (first p))
903 (match1 (node-parameters n) (second p))
904 (let loop ((ns (node-subexpressions n))
905 (ps (cddr p)) )
906 (cond ((null? ps) (null? ns))
907 ((not (pair? ps)) (resolve ps ns))
908 ((null? ns) #f)
909 (else (and (matchn (car ns) (car ps))
910 (loop (cdr ns) (cdr ps)) ) ) ) ) ) ) )
911
912 (let ((r (matchn node pat)))
913 (and r
914 (begin
915 (debugging 'a "matched" (node-class node) (node-parameters node) pat)
916 env) ) ) ) )
917
918
919;;; Test nodes for certain properties:
920
921(define (expression-has-side-effects? node db)
922 (let walk ([n node])
923 (let ([subs (node-subexpressions n)])
924 (case (node-class n)
925 [(##core#variable quote ##core#undefined ##core#proc) #f]
926 [(##core#lambda)
927 (let ([id (first (node-parameters n))])
928 (find (lambda (fs)
929 (eq? id (foreign-callback-stub-id fs)))
930 foreign-callback-stubs) ) ]
931 [(if let) (any walk subs)]
932 [else #t] ) ) ) )
933
934(define (simple-lambda-node? node) ; Used only in compiler.scm
935 (let* ([params (node-parameters node)]
936 [llist (third params)]
937 [k (and (pair? llist) (first llist))] ) ; leaf-routine has no continuation argument
938 (and k
939 (second params)
940 (let rec ([n node])
941 (case (node-class n)
942 [(##core#call)
943 (let* ([subs (node-subexpressions n)]
944 [f (first subs)] )
945 (and (eq? '##core#variable (node-class f))
946 (eq? k (first (node-parameters f)))
947 (every rec (cdr subs)) ) ) ]
948 [(##core#callunit) #f]
949 [else (every rec (node-subexpressions n))] ) ) ) ) )
950
951
952;;; Some safety checks and database dumping:
953
954(define (dump-undefined-globals db) ; Used only in batch-driver.scm
955 (hash-table-for-each
956 (lambda (sym plist)
957 (when (and (not (keyword? sym))
958 (assq 'global plist)
959 (not (assq 'assigned plist)) )
960 (write sym)
961 (newline) ) )
962 db) )
963
964(define (dump-defined-globals db) ; Used only in batch-driver.scm
965 (hash-table-for-each
966 (lambda (sym plist)
967 (when (and (not (keyword? sym))
968 (assq 'global plist)
969 (assq 'assigned plist))
970 (write sym)
971 (newline) ) )
972 db) )
973
974(define (dump-global-refs db) ; Used only in batch-driver.scm
975 (hash-table-for-each
976 (lambda (sym plist)
977 (when (and (not (keyword? sym)) (assq 'global plist))
978 (let ((a (assq 'references plist)))
979 (write (list sym (if a (length (cdr a)) 0)))
980 (newline) ) ) )
981 db) )
982
983
984;;; change hook function to hide non-exported module bindings
985
986(set! ##sys#toplevel-definition-hook
987 (lambda (sym renamed exported?)
988 (cond ((namespaced-symbol? sym)
989 (unhide-variable sym))
990 ((not exported?)
991 (debugging 'o "hiding unexported module binding" renamed)
992 (hide-variable renamed)))))
993
994
995;;; Foreign callback stub and type tables:
996
997(define foreign-callback-stubs '())
998
999(define-record-type foreign-callback-stub
1000 (make-foreign-callback-stub id name qualifiers return-type argument-types)
1001 foreign-callback-stub?
1002 (id foreign-callback-stub-id) ; symbol
1003 (name foreign-callback-stub-name) ; string
1004 (qualifiers foreign-callback-stub-qualifiers) ; string
1005 (return-type foreign-callback-stub-return-type) ; type-specifier
1006 (argument-types foreign-callback-stub-argument-types)) ; (type-specifier ...)
1007
1008(define (register-foreign-callback-stub! id params)
1009 (set! foreign-callback-stubs
1010 (cons (apply make-foreign-callback-stub id params) foreign-callback-stubs) )
1011 ;; mark to avoid leaf-routine optimization
1012 (mark-variable id '##compiler#callback-lambda))
1013
1014(define-constant foreign-type-table-size 301)
1015
1016(define foreign-type-table #f)
1017
1018(define (clear-foreign-type-table!)
1019 (if foreign-type-table
1020 (vector-fill! foreign-type-table '())
1021 (set! foreign-type-table (make-vector foreign-type-table-size '())) ))
1022
1023;; Register a foreign type under the given alias. type is the foreign
1024;; type's name, arg and ret are the *names* of conversion procedures
1025;; when this type is used as argument or return value, respectively.
1026;; The latter two must either both be supplied, or neither.
1027;; TODO: Maybe create a separate record type for foreign types?
1028(define (register-foreign-type! alias type #!optional arg ret)
1029 (hash-table-set! foreign-type-table alias
1030 (vector type (and ret arg) (and arg ret))))
1031
1032;; Returns either #f (if t does not exist) or a vector with the type,
1033;; the *name* of the argument conversion procedure and the *name* of
1034;; the return value conversion procedure. If no conversion procedures
1035;; have been supplied, the corresponding slots will be #f.
1036(define (lookup-foreign-type t)
1037 (hash-table-ref foreign-type-table t))
1038
1039;;; Create foreign type checking expression:
1040
1041(define foreign-type-check ; Used only in compiler.scm
1042 (let ((tmap '((nonnull-u8vector . u8vector) (nonnull-u16vector . u16vector)
1043 (nonnull-s8vector . s8vector) (nonnull-s16vector . s16vector)
1044 (nonnull-u32vector . u32vector) (nonnull-s32vector . s32vector)
1045 (nonnull-u64vector . u64vector) (nonnull-s64vector . s64vector)
1046 (nonnull-f32vector . f32vector) (nonnull-f64vector . f64vector)))
1047 (ftmap '((integer . "int") (unsigned-integer . "unsigned int")
1048 (integer32 . "C_s32") (unsigned-integer32 . "C_u32")
1049 (integer64 . "C_s64") (unsigned-integer64 . "C_u64")
1050 (short . "short") (unsigned-short . "unsigned short")
1051 (long . "long") (unsigned-long . "unsigned long")
1052 (ssize_t . "ssize_t") (size_t . "size_t"))))
1053 (lambda (param type)
1054 (follow-without-loop
1055 type
1056 (lambda (t next)
1057 (let repeat ((t t))
1058 (case t
1059 ((char unsigned-char) (if unsafe param `(##sys#foreign-char-argument ,param)))
1060 ;; TODO: Should "[unsigned-]byte" be range checked?
1061 ((int unsigned-int byte unsigned-byte int32 unsigned-int32)
1062 (if unsafe param `(##sys#foreign-fixnum-argument ,param)))
1063 ((float double number) (if unsafe param `(##sys#foreign-flonum-argument ,param)))
1064 ((blob scheme-pointer)
1065 (let ((tmp (gensym)))
1066 `(##core#let ((,tmp ,param))
1067 (##core#if ,tmp
1068 ,(if unsafe
1069 tmp
1070 `(##sys#foreign-block-argument ,tmp) )
1071 (##core#quote #f)) ) ) )
1072 ((nonnull-scheme-pointer nonnull-blob)
1073 (if unsafe
1074 param
1075 `(##sys#foreign-block-argument ,param) ) )
1076 ((pointer-vector)
1077 (let ((tmp (gensym)))
1078 `(##core#let ((,tmp ,param))
1079 (##core#if ,tmp
1080 ,(if unsafe
1081 tmp
1082 `(##sys#foreign-struct-wrapper-argument (##core#quote pointer-vector) ,tmp) )
1083 (##core#quote #f)) ) ) )
1084 ((nonnull-pointer-vector)
1085 (if unsafe
1086 param
1087 `(##sys#foreign-struct-wrapper-argument (##core#quote pointer-vector) ,param) ) )
1088 ((u8vector u16vector s8vector s16vector u32vector s32vector
1089 u64vector s64vector f32vector f64vector)
1090 (let ((tmp (gensym)))
1091 `(##core#let ((,tmp ,param))
1092 (##core#if ,tmp
1093 ,(if unsafe
1094 tmp
1095 `(##sys#foreign-struct-wrapper-argument (##core#quote ,t) ,tmp) )
1096 (##core#quote #f)) ) ) )
1097 ((nonnull-u8vector nonnull-u16vector
1098 nonnull-s8vector nonnull-s16vector
1099 nonnull-u32vector nonnull-s32vector
1100 nonnull-u64vector nonnull-s64vector
1101 nonnull-f32vector nonnull-f64vector)
1102 (if unsafe
1103 param
1104 `(##sys#foreign-struct-wrapper-argument
1105 (##core#quote ,(##sys#slot (assq t tmap) 1))
1106 ,param) ) )
1107 ((integer32 integer64 integer short long ssize_t)
1108 (let* ((foreign-type (##sys#slot (assq t ftmap) 1))
1109 (size-expr (sprintf "sizeof(~A) * CHAR_BIT" foreign-type)))
1110 (if unsafe
1111 param
1112 `(##sys#foreign-ranged-integer-argument
1113 ,param (foreign-value ,size-expr int)))))
1114 ((unsigned-short unsigned-long unsigned-integer size_t
1115 unsigned-integer32 unsigned-integer64)
1116 (let* ((foreign-type (##sys#slot (assq t ftmap) 1))
1117 (size-expr (sprintf "sizeof(~A) * CHAR_BIT" foreign-type)))
1118 (if unsafe
1119 param
1120 `(##sys#foreign-unsigned-ranged-integer-argument
1121 ,param (foreign-value ,size-expr int)))))
1122 ((c-pointer c-string-list c-string-list*)
1123 (let ((tmp (gensym)))
1124 `(##core#let ((,tmp ,param))
1125 (##core#if ,tmp
1126 (##sys#foreign-pointer-argument ,tmp)
1127 (##core#quote #f)) ) ) )
1128 ((nonnull-c-pointer)
1129 `(##sys#foreign-pointer-argument ,param) )
1130 ((c-string c-string* unsigned-c-string unsigned-c-string*)
1131 (let ((tmp (gensym)))
1132 `(##core#let ((,tmp ,param))
1133 (##core#if ,tmp
1134 ,(if unsafe
1135 `(##sys#make-c-string ,tmp)
1136 `(##sys#make-c-string (##sys#foreign-string-argument ,tmp)) )
1137 (##core#quote #f)) ) ) )
1138 ((nonnull-c-string nonnull-c-string* nonnull-unsigned-c-string*)
1139 (if unsafe
1140 `(##sys#make-c-string ,param)
1141 `(##sys#make-c-string (##sys#foreign-string-argument ,param)) ) )
1142 ((symbol)
1143 (if unsafe
1144 `(##sys#make-c-string (##sys#symbol->string ,param))
1145 `(##sys#make-c-string (##sys#foreign-string-argument (##sys#symbol->string ,param))) ) )
1146 (else
1147 (cond ((and (symbol? t) (lookup-foreign-type t))
1148 => (lambda (t) (next (vector-ref t 0)) ) )
1149 ((pair? t)
1150 (case (car t)
1151 ((ref pointer function c-pointer)
1152 (let ((tmp (gensym)))
1153 `(##core#let ((,tmp ,param))
1154 (##core#if ,tmp
1155 (##sys#foreign-pointer-argument ,tmp)
1156 (##core#quote #f)) ) ) )
1157 ((instance instance-ref)
1158 (let ((tmp (gensym)))
1159 `(##core#let ((,tmp ,param))
1160 (##core#if ,tmp
1161 (slot-ref ,param (##core#quote this))
1162 (##core#quote #f)) ) ) )
1163 ((scheme-pointer)
1164 (let ((tmp (gensym)))
1165 `(##core#let ((,tmp ,param))
1166 (##core#if ,tmp
1167 ,(if unsafe
1168 tmp
1169 `(##sys#foreign-block-argument ,tmp) )
1170 (##core#quote #f)) ) ) )
1171 ((nonnull-scheme-pointer)
1172 (if unsafe
1173 param
1174 `(##sys#foreign-block-argument ,param) ) )
1175 ((nonnull-instance)
1176 `(slot-ref ,param (##core#quote this)) )
1177 ((const) (repeat (cadr t)))
1178 ((enum)
1179 (if unsafe
1180 param
1181 `(##sys#foreign-ranged-integer-argument
1182 ;; enums are integer size, according to the C standard.
1183 ,param (foreign-value "sizeof(int) * CHAR_BIT" int))))
1184 ((nonnull-pointer nonnull-c-pointer)
1185 `(##sys#foreign-pointer-argument ,param) )
1186 (else param) ) )
1187 (else param) ) ) ) ) )
1188 (lambda ()
1189 (quit-compiling "foreign type `~S' refers to itself" type)) ) ) ) )
1190
1191
1192;;; Compute foreign-type conversions:
1193
1194(define (foreign-type-result-converter t)
1195 (and-let* (((symbol? t))
1196 (ft (lookup-foreign-type t))
1197 (retconv (vector-ref ft 2)) )
1198 retconv))
1199
1200(define (foreign-type-argument-converter t)
1201 (and-let* (((symbol? t))
1202 (ft (lookup-foreign-type t))
1203 (argconv (vector-ref ft 1)) )
1204 argconv))
1205
1206(define (foreign-type-convert-result r t) ; Used only in compiler.scm
1207 (or (and-let* ((retconv (foreign-type-result-converter t)))
1208 (list retconv r) )
1209 r) )
1210
1211(define (foreign-type-convert-argument a t) ; Used only in compiler.scm
1212 (or (and-let* ((argconv (foreign-type-argument-converter t)) )
1213 (list argconv a) )
1214 a) )
1215
1216(define (final-foreign-type t0) ; Used here and in compiler.scm
1217 (follow-without-loop
1218 t0
1219 (lambda (t next)
1220 (cond ((and (symbol? t) (lookup-foreign-type t))
1221 => (lambda (t2) (next (vector-ref t2 0)) ) )
1222 (else t) ) )
1223 (lambda () (quit-compiling "foreign type `~S' refers to itself" t0)) ) )
1224
1225
1226;;; Compute foreign result size:
1227
1228(define (estimate-foreign-result-size type)
1229 (define (err t)
1230 (quit-compiling "cannot compute size for unknown foreign type `~S' result" type))
1231 (follow-without-loop
1232 type
1233 (lambda (t next)
1234 (case t
1235 ((char int short bool void unsigned-short scheme-object unsigned-char unsigned-int byte unsigned-byte
1236 int32 unsigned-int32)
1237 0)
1238 ((c-string nonnull-c-string c-pointer nonnull-c-pointer symbol c-string* nonnull-c-string*
1239 unsigned-c-string unsigned-c-string* nonnull-unsigned-c-string*
1240 c-string-list c-string-list*)
1241 (words->bytes 3) )
1242 ((unsigned-integer long integer unsigned-long integer32 unsigned-integer32)
1243 (words->bytes 6) ) ; 1 bignum digit on 32-bit (overallocs on 64-bit)
1244 ((float double number)
1245 (words->bytes 4) ) ; possibly 8-byte aligned 64-bit double
1246 ((integer64 unsigned-integer64 size_t ssize_t)
1247 (words->bytes 7)) ; 2 bignum digits on 32-bit (overallocs on 64-bit)
1248 (else
1249 (cond ((and (symbol? t) (lookup-foreign-type t))
1250 => (lambda (t2) (next (vector-ref t2 0)) ) )
1251 ((pair? t)
1252 (case (car t)
1253 ((ref nonnull-pointer pointer c-pointer nonnull-c-pointer function instance instance-ref nonnull-instance)
1254 (words->bytes 3) )
1255 ((const) (next (cadr t)))
1256 ((enum) (words->bytes 6)) ; 1 bignum digit on 32-bit (overallocs on 64-bit)
1257 (else (err t))))
1258 (else (err t))))))
1259 (lambda () (quit-compiling "foreign type `~S' refers to itself" type)) ) )
1260
1261(define (estimate-foreign-result-location-size type) ; Used only in compiler.scm
1262 (define (err t)
1263 (quit-compiling "cannot compute size of location for foreign type `~S'" t) )
1264 (follow-without-loop
1265 type
1266 (lambda (t next)
1267 (case t
1268 ((char int short bool unsigned-short unsigned-char unsigned-int long unsigned-long byte
1269 unsigned-byte c-pointer nonnull-c-pointer unsigned-integer integer float c-string symbol
1270 scheme-pointer nonnull-scheme-pointer int32 unsigned-int32 integer32 unsigned-integer32
1271 unsigned-c-string unsigned-c-string* nonnull-unsigned-c-string*
1272 nonnull-c-string c-string* nonnull-c-string* c-string-list c-string-list*)
1273 (words->bytes 1) )
1274 ((double integer64 unsigned-integer64 size_t ssize_t)
1275 (words->bytes 2) )
1276 (else
1277 (cond ((and (symbol? t) (lookup-foreign-type t))
1278 => (lambda (t2) (next (vector-ref t2 0)) ) )
1279 ((pair? t)
1280 (case (car t)
1281 ((ref nonnull-pointer pointer c-pointer nonnull-c-pointer function
1282 scheme-pointer nonnull-scheme-pointer enum)
1283 (words->bytes 1))
1284 ((const) (next (cadr t)))
1285 (else (err t)) ) )
1286 (else (err t)) ) ) ) )
1287 (lambda () (quit-compiling "foreign type `~S' refers to itself" type)) ) )
1288
1289
1290;;; Convert result value, if a string:
1291
1292(define (finish-foreign-result type body) ; Used only in compiler.scm
1293 (let ((type (strip-syntax type)))
1294 (case type
1295 ((c-string unsigned-c-string) `(##sys#peek-c-string ,body (##core#quote 0)))
1296 ((nonnull-c-string) `(##sys#peek-nonnull-c-string ,body (##core#quote 0)))
1297 ((c-string* unsigned-c-string*) `(##sys#peek-and-free-c-string ,body (##core#quote 0)))
1298 ((nonnull-c-string* nonnull-unsigned-c-string*) `(##sys#peek-and-free-nonnull-c-string ,body (##core#quote 0)))
1299 ((symbol) `(##sys#intern-symbol (##sys#peek-c-string ,body (##core#quote 0))))
1300 ((c-string-list) `(##sys#peek-c-string-list ,body (##core#quote #f)))
1301 ((c-string-list*) `(##sys#peek-and-free-c-string-list ,body (##core#quote #f)))
1302 (else
1303 (if (list? type)
1304 (if (and (eq? (car type) 'const)
1305 (= 2 (length type))
1306 (memq (cadr type) '(c-string c-string* unsigned-c-string
1307 unsigned-c-string* nonnull-c-string
1308 nonnull-c-string*
1309 nonnull-unsigned-string*)))
1310 (finish-foreign-result (cadr type) body)
1311 (if (= 3 (length type))
1312 (case (car type)
1313 ((instance instance-ref)
1314 (let ((tmp (gensym)))
1315 `(let ((,tmp ,body))
1316 (and ,tmp
1317 (not (##sys#null-pointer? ,tmp))
1318 (make ,(caddr type)
1319 (##core#quote this) ,tmp) ) ) ) )
1320 ((nonnull-instance)
1321 `(make ,(caddr type) (##core#quote this) ,body) )
1322 (else body))
1323 body))
1324 body)))))
1325
1326
1327;;; Translate foreign-type into scrutinizer type:
1328
1329;; Used in chicken-ffi-syntax.scm and scrutinizer.scm
1330(define (foreign-type->scrutiny-type t mode) ; MODE = 'arg | 'result
1331 ;; If the foreign type has a converter, it can return a different
1332 ;; type from the native type matching the foreign type (see #1649)
1333 (if (or (and (eq? mode 'arg) (foreign-type-argument-converter t))
1334 (and (eq? mode 'result) (foreign-type-result-converter t)))
1335 ;; Here we just punt on the type, but it would be better to
1336 ;; find out the result type of the converter procedure.
1337 '*
1338 (let ((ft (final-foreign-type t)))
1339 (case ft
1340 ((void) 'undefined)
1341 ((char unsigned-char) 'char)
1342 ((int unsigned-int short unsigned-short byte unsigned-byte int32 unsigned-int32)
1343 'fixnum)
1344 ((float double)
1345 (case mode
1346 ((arg) 'number)
1347 (else 'float)))
1348 ((scheme-pointer nonnull-scheme-pointer) '*)
1349 ((blob)
1350 (case mode
1351 ((arg) '(or false blob))
1352 (else 'blob)))
1353 ((nonnull-blob) 'blob)
1354 ((pointer-vector)
1355 (case mode
1356 ((arg) '(or false pointer-vector))
1357 (else 'pointer-vector)))
1358 ((nonnull-pointer-vector) 'pointer-vector)
1359 ((u8vector u16vector s8vector s16vector u32vector s32vector u64vector s64vector f32vector f64vector)
1360 (case mode
1361 ((arg) `(or false (struct ,ft)))
1362 (else `(struct ,ft))))
1363 ((nonnull-u8vector) '(struct u8vector))
1364 ((nonnull-s8vector) '(struct s8vector))
1365 ((nonnull-u16vector) '(struct u16vector))
1366 ((nonnull-s16vector) '(struct s16vector))
1367 ((nonnull-u32vector) '(struct u32vector))
1368 ((nonnull-s32vector) '(struct s32vector))
1369 ((nonnull-u64vector) '(struct u64vector))
1370 ((nonnull-s64vector) '(struct s64vector))
1371 ((nonnull-f32vector) '(struct f32vector))
1372 ((nonnull-f64vector) '(struct f64vector))
1373 ((integer long size_t ssize_t integer32 unsigned-integer32 integer64 unsigned-integer64
1374 unsigned-long)
1375 'integer)
1376 ((c-pointer)
1377 (if (eq? 'arg mode)
1378 '(or false pointer locative)
1379 '(or false pointer)))
1380 ((nonnull-c-pointer)
1381 (if (eq? 'arg mode)
1382 '(or pointer locative)
1383 'pointer))
1384 ((c-string c-string* unsigned-c-string unsigned-c-string*)
1385 '(or false string))
1386 ((c-string-list c-string-list*)
1387 '(list-of string))
1388 ((nonnull-c-string nonnull-c-string* nonnull-unsigned-c-string*) 'string)
1389 ((symbol) 'symbol)
1390 (else
1391 (cond ((pair? t)
1392 (case (car t)
1393 ((ref pointer function c-pointer)
1394 (if (eq? 'arg mode)
1395 '(or false pointer locative)
1396 '(or false pointer)))
1397 ((const) (foreign-type->scrutiny-type (cadr t) mode))
1398 ((enum) 'integer)
1399 ((nonnull-pointer nonnull-c-pointer)
1400 (if (eq? 'arg mode)
1401 '(or pointer locative)
1402 'pointer))
1403 (else '*)))
1404 (else '*)))))))
1405
1406
1407;;; Scan expression-node for variable usage:
1408
1409(define (scan-used-variables node vars)
1410 (let ([used '()])
1411 (let walk ([n node])
1412 (let ([subs (node-subexpressions n)])
1413 (case (node-class n)
1414 [(##core#variable set!)
1415 (let ([var (first (node-parameters n))])
1416 (when (and (memq var vars) (not (memq var used)))
1417 (set! used (cons var used)) )
1418 (for-each walk subs) ) ]
1419 [(quote ##core#undefined ##core#primitive) #f]
1420 [else (for-each walk subs)] ) ) )
1421 used) )
1422
1423
1424;;; Scan expression-node for free variables (that are not in env):
1425
1426(define (scan-free-variables node block-compilation)
1427 (let ((vars '())
1428 (hvars '()))
1429
1430 (define (walk n e)
1431 (let ([subs (node-subexpressions n)]
1432 [params (node-parameters n)] )
1433 (case (node-class n)
1434 ((quote ##core#undefined ##core#primitive ##core#proc ##core#inline_ref) #f)
1435 ((##core#variable)
1436 (let ((var (first params)))
1437 (unless (memq var e)
1438 (set! vars (lset-adjoin/eq? vars var))
1439 (unless (variable-visible? var block-compilation)
1440 (set! hvars (lset-adjoin/eq? hvars var))))))
1441 ((set!)
1442 (let ((var (first params)))
1443 (unless (memq var e) (set! vars (lset-adjoin/eq? vars var)))
1444 (walk (car subs) e) ) )
1445 ((let)
1446 (walk (first subs) e)
1447 (walk (second subs) (append params e)) )
1448 ((##core#lambda)
1449 (##sys#decompose-lambda-list
1450 (third params)
1451 (lambda (vars argc rest)
1452 (walk (first subs) (append vars e)) ) ) )
1453 (else (walkeach subs e)) ) ) )
1454
1455 (define (walkeach ns e)
1456 (for-each (lambda (n) (walk n e)) ns) )
1457
1458 (walk node '())
1459 (values vars hvars) ) ) ; => freevars hiddenvars
1460
1461
1462;;; Special block-variable literal type:
1463
1464(define-record-type block-variable-literal
1465 (make-block-variable-literal name)
1466 block-variable-literal?
1467 (name block-variable-literal-name)) ; symbol
1468
1469
1470;;; Generation of random names:
1471
1472;; This one looks iffy. It's also used only in compiler.scm
1473(define (make-random-name . prefix)
1474 (string->symbol
1475 (sprintf "~A-~A~A"
1476 (optional prefix (gensym))
1477 (current-seconds)
1478 (##core#inline "C_random_fixnum" 1000))))
1479
1480
1481;;; Register/lookup real names:
1482;
1483; - The real-name-table contains the following mappings:
1484;
1485; <variable-alias> -> <variable>
1486; <lambda-id> -> <variable> or <variable-alias>
1487
1488(define-constant real-name-table-size 997)
1489
1490(define real-name-table #f)
1491
1492(define (clear-real-name-table!)
1493 (set! real-name-table (make-vector real-name-table-size '())))
1494
1495(define (set-real-name! name rname) ; Used only in compiler.scm
1496 (hash-table-set! real-name-table name rname))
1497
1498;; TODO: Find out why there are so many lookup functions for this and
1499;; reduce them to the minimum.
1500(define (get-real-name name)
1501 (hash-table-ref real-name-table name))
1502
1503;; Arbitrary limit to prevent runoff into exponential behavior
1504(define real-name-max-depth 20)
1505
1506(define (real-name var . db)
1507 (define (resolve n)
1508 (let ((n2 (hash-table-ref real-name-table n)))
1509 (if n2
1510 (or (hash-table-ref real-name-table n2)
1511 n2)
1512 n) ) )
1513 (let ((rn (resolve var)))
1514 (cond ((not rn) (##sys#symbol->string var))
1515 ((pair? db)
1516 (let ((db (car db)))
1517 (let loop ((nesting (list (##sys#symbol->string rn)))
1518 (depth 0)
1519 (container (db-get db var 'contained-in)) )
1520 (cond
1521 ((> depth real-name-max-depth)
1522 (string-intersperse (reverse (cons "..." nesting)) " in "))
1523 (container
1524 (let ((rc (resolve container)))
1525 (if (eq? rc container)
1526 (string-intersperse (reverse nesting) " in ")
1527 (loop (cons (symbol->string rc) nesting)
1528 (fx+ depth 1)
1529 (db-get db container 'contained-in) ) ) ))
1530 (else (string-intersperse (reverse nesting) " in "))) ) ) )
1531 (else (##sys#symbol->string rn)) ) ) )
1532
1533(define (real-name2 var db) ; Used only in c-backend.scm
1534 (and-let* ((rn (hash-table-ref real-name-table var)))
1535 (real-name rn db) ) )
1536
1537(define (display-real-name-table)
1538 (hash-table-for-each
1539 (lambda (key val)
1540 (printf "~S\t~S~%" key val) )
1541 real-name-table) )
1542
1543(define (source-info->string info) ; Used only in c-backend.scm
1544 (if (list? info)
1545 (let ((ln (car info))
1546 (name (cadr info)))
1547 (conc ln ":" (make-string (max 0 (- 4 (string-length ln))) #\space) " " name) )
1548 (->string info)))
1549
1550(define (source-info->name info)
1551 (if (list? info) (cadr info) (->string info)))
1552
1553(define (source-info->line info)
1554 (and (list? info) (car info)))
1555
1556(define (call-info params var) ; Used only in optimizer.scm
1557 (or (and-let* ((info (and (pair? (cdr params)) (second params))))
1558 (and (list? info)
1559 (let ((ln (car info))
1560 (name (cadr info)))
1561 (conc "(" ln ") " var))))
1562 var))
1563
1564
1565;;; constant folding support:
1566
1567(define (constant-form-eval op argnodes k) ; Used only in optimizer.scm
1568 (let* ((args (map (lambda (n) (first (node-parameters n))) argnodes))
1569 (form (cons op (map (lambda (arg) `(quote ,arg)) args))))
1570 ;; op must have toplevel binding, result must be single-valued
1571 (let ((proc (##sys#slot op 0)))
1572 (if (procedure? proc)
1573 (let ((results (handle-exceptions ex ex (receive (apply proc args)))))
1574 (cond ((condition? results) (k #f #f))
1575 ((and (= 1 (length results))
1576 (encodeable-literal? (car results)))
1577 (debugging 'o "folded constant expression" form)
1578 (k #t (car results)))
1579 ((= 1 (length results)) ; not encodeable; don't fold
1580 (k #f #f))
1581 (else
1582 (bomb "attempt to constant-fold call to procedure that has multiple results" form))))
1583 (bomb "attempt to constant-fold call to non-procedure" form)))))
1584
1585(define (maybe-constant-fold-call n subs k)
1586 (define (constant-node? n2) (eq? 'quote (node-class n2)))
1587 (if (eq? '##core#variable (node-class (car subs)))
1588 (let ((var (first (node-parameters (car subs)))))
1589 (if (and (intrinsic? var)
1590 (or (foldable? var)
1591 (predicate? var))
1592 (every constant-node? (cdr subs)) )
1593 (constant-form-eval var (cdr subs) (lambda (ok res) (k ok res #t)))
1594 (k #f #f #f)))
1595 (k #f #f #f)))
1596
1597;; Is the literal small enough to be encoded? Otherwise, it should
1598;; not be constant-folded.
1599(define (encodeable-literal? lit)
1600 (define getsize
1601 (foreign-lambda* int ((scheme-object lit))
1602 "return(C_header_size(lit));"))
1603 (define (fits? n)
1604 (fx<= (integer-length n) 24))
1605 (cond ((immediate? lit))
1606 ((exact-integer? lit)
1607 ;; Could use integer-length, but that's trickier (minus
1608 ;; symbol etc). If the string is too large to allocate,
1609 ;; we'll also get an exception!
1610 (let ((str (handle-exceptions ex #f (number->string lit 16))))
1611 (and str (fits? (string-length str)))))
1612 ((flonum? lit))
1613 ((symbol? lit)
1614 (let ((str (##sys#slot lit 1)))
1615 (fits? (string-length str))))
1616 ((##core#inline "C_byteblockp" lit)
1617 (fits? (getsize lit)))
1618 (else
1619 (let ((len (getsize lit)))
1620 (and (fits? len)
1621 (every
1622 encodeable-literal?
1623 (list-tabulate len (lambda (i)
1624 (##sys#slot lit i)))))))))
1625
1626
1627;;; Dump node structure:
1628
1629(define (dump-nodes n) ; Used only in batch-driver.scm
1630 (let loop ([i 0] [n n])
1631 (let ([class (node-class n)]
1632 [params (node-parameters n)]
1633 [subs (node-subexpressions n)]
1634 [ind (make-string i #\space)]
1635 [i2 (+ i 2)] )
1636 (printf "~%~A<~A ~S" ind class params)
1637 (for-each (cut loop i2 <>) subs)
1638 (let ([len (##sys#size n)])
1639 (when (fx> len 4)
1640 (printf "[~S" (##sys#slot n 4))
1641 (do ([i 5 (fx+ i 1)])
1642 ((fx>= i len))
1643 (printf " ~S" (##sys#slot n i)) )
1644 (write-char #\]) ) )
1645 (write-char #\>) ) )
1646 (newline) )
1647
1648
1649;; DEPRECATED
1650(define (read/source-info in)
1651 (chicken.syntax#read-with-source-info in) )
1652
1653;;; "#> ... <#" syntax:
1654
1655(set! ##sys#user-read-hook
1656 (let ([old-hook ##sys#user-read-hook])
1657 (lambda (char port)
1658 (if (char=? #\> char)
1659 (let* ((_ (read-char port)) ; swallow #\>
1660 (text (scan-sharp-greater-string port)))
1661 `(declare (foreign-declare ,text)) )
1662 (old-hook char port) ) ) ) )
1663
1664(define (scan-sharp-greater-string port)
1665 (let ([out (open-output-string)])
1666 (let loop ()
1667 (let ((c (read-char port)))
1668 (cond ((eof-object? c)
1669 (quit-compiling "unexpected end of `#> ... <#' sequence"))
1670 ((char=? c #\newline)
1671 (newline out)
1672 (loop) )
1673 ((char=? c #\<)
1674 (let ([c (read-char port)])
1675 (if (eqv? #\# c)
1676 (get-output-string out)
1677 (begin
1678 (write-char #\< out)
1679 (write-char c out)
1680 (loop) ) ) ) )
1681 (else
1682 (write-char c out)
1683 (loop) ) ) ) ) ) )
1684
1685
1686;;; 64-bit fixnum?
1687
1688(define (big-fixnum? x) ;; XXX: This should probably be in c-platform
1689 (and (fixnum? x)
1690 (feature? #:64bit)
1691 (or (fx> x 1073741823)
1692 (fx< x -1073741824) ) ) )
1693
1694(define (small-bignum? x) ;; XXX: This should probably be in c-platform
1695 (and (bignum? x)
1696 (not (feature? #:64bit))
1697 (fx<= (integer-length x) 62) ) )
1698
1699
1700;;; symbol visibility and other global variable properties
1701
1702(define (hide-variable sym) ; Used in compiler.scm and here
1703 (mark-variable sym '##compiler#visibility 'hidden))
1704
1705(define (export-variable sym) ; Used only in compiler.scm
1706 (mark-variable sym '##compiler#visibility 'exported))
1707
1708(define (variable-hidden? sym)
1709 (eq? (##sys#get sym '##compiler#visibility) 'hidden))
1710
1711(define (unhide-variable sym)
1712 (when (variable-hidden? sym) (remprop! sym '##compiler#visibility)))
1713
1714(define (variable-visible? sym block-compilation)
1715 (let ((p (##sys#get sym '##compiler#visibility)))
1716 (case p
1717 ((hidden) #f)
1718 ((exported) #t)
1719 (else (not block-compilation)))))
1720
1721;; These two have somewhat confusing names. Maybe mark-variable could
1722;; be renamed to "variable-mark-set!"? Also, in some other situations,
1723;; put!/get are used directly.
1724(define (mark-variable var mark #!optional (val #t))
1725 (##sys#put! var mark val) )
1726
1727(define (variable-mark var mark)
1728 (##sys#get var mark) )
1729
1730(define intrinsic? (cut variable-mark <> '##compiler#intrinsic))
1731;; Used only in optimizer.scm
1732(define foldable? (cut variable-mark <> '##compiler#foldable))
1733(define predicate? (cut variable-mark <> '##compiler#predicate))
1734
1735
1736;;; Load support files
1737
1738(define (load-identifier-database name) ; Used only in batch-driver.scm
1739 (and-let* ((dbfile (chicken.load#find-file name (repository-path))))
1740 (debugging 'p (sprintf "loading identifier database ~a ...~%" dbfile))
1741 (for-each
1742 (lambda (e)
1743 (let ((id (car e)))
1744 (##sys#put!
1745 id '##core#db
1746 (append (or (##sys#get id '##core#db) '()) (list (cdr e))) )))
1747 (call-with-input-file dbfile read-expressions))))
1748
1749
1750;;; Print version/usage information:
1751
1752(define (print-version #!optional b) ; Used only in batch-driver.scm
1753 (when b (print* +banner+))
1754 (print (chicken-version #t)) )
1755
1756;; Used only in batch-driver.scm, but it seems to me this should be moved
1757;; to chicken.scm, as that's the only place this belongs.
1758(define (print-usage)
1759 (print-version)
1760 (newline)
1761 (display #<<EOF
1762Usage: chicken FILENAME [OPTION ...]
1763
1764 `chicken' is the CHICKEN compiler.
1765
1766 FILENAME should be a complete source file name with extension, or "-" for
1767 standard input. OPTION may be one of the following:
1768
1769 General options:
1770
1771 -help display this text and exit
1772 -version display compiler version and exit
1773 -release print release number and exit
1774 -verbose display information on compilation progress
1775
1776 File and pathname options:
1777
1778 -output-file FILENAME specifies output-filename, default is 'out.c'
1779 -include-path PATHNAME specifies alternative path for included files
1780 -to-stdout write compiled file to stdout instead of file
1781
1782 Language options:
1783
1784 -feature SYMBOL register feature identifier
1785 -no-feature SYMBOL disable built-in feature identifier
1786
1787 Syntax related options:
1788
1789 -case-insensitive don't preserve case of read symbols
1790 -keyword-style STYLE allow alternative keyword syntax
1791 (prefix, suffix or none)
1792 -no-parentheses-synonyms disables list delimiter synonyms
1793 -no-symbol-escape disables support for escaped symbols
1794 -r5rs-syntax disables the CHICKEN extensions to
1795 R5RS syntax
1796 -compile-syntax macros are made available at run-time
1797 -emit-import-library MODULE write compile-time module information into
1798 separate file
1799 -emit-all-import-libraries emit import-libraries for all defined modules
1800 -no-compiler-syntax disable expansion of compiler-macros
1801 -module NAME wrap compiled code in a module
1802 -module-registration always generate module registration code
1803 -no-module-registration never generate module registration code
1804 (overrides `-module-registration')
1805
1806 Translation options:
1807
1808 -explicit-use do not use units 'library' and 'eval' by
1809 default
1810 -check-syntax stop compilation after macro-expansion
1811 -analyze-only stop compilation after first analysis pass
1812
1813 Debugging options:
1814
1815 -no-warnings disable warnings
1816 -debug-level NUMBER set level of available debugging information
1817 -no-trace disable tracing information
1818 -debug-info enable debug-information in compiled code for use
1819 with an external debugger
1820 -profile executable emits profiling information
1821 -profile-name FILENAME name of the generated profile information file
1822 -accumulate-profile executable emits profiling information in
1823 append mode
1824 -no-lambda-info omit additional procedure-information
1825 -emit-types-file FILENAME write type-declaration information into file
1826 -consult-types-file FILENAME load additional type database
1827
1828 Optimization options:
1829
1830 -optimize-level NUMBER enable certain sets of optimization options
1831 -optimize-leaf-routines enable leaf routine optimization
1832 -no-usual-integrations standard procedures may be redefined
1833 -unsafe disable all safety checks
1834 -local assume globals are only modified in current
1835 file
1836 -block enable block-compilation
1837 -disable-interrupts disable interrupts in compiled code
1838 -fixnum-arithmetic assume all numbers are fixnums
1839 -disable-stack-overflow-checks disables detection of stack-overflows
1840 -inline enable inlining
1841 -inline-limit LIMIT set inlining threshold
1842 -inline-global enable cross-module inlining
1843 -specialize perform type-based specialization of primitive calls
1844 -emit-inline-file FILENAME generate file with globally inlinable
1845 procedures (implies -inline -local)
1846 -consult-inline-file FILENAME explicitly load inline file
1847 -no-argc-checks disable argument count checks
1848 -no-bound-checks disable bound variable checks
1849 -no-procedure-checks disable procedure call checks
1850 -no-procedure-checks-for-usual-bindings
1851 disable procedure call checks only for usual
1852 bindings
1853 -no-procedure-checks-for-toplevel-bindings
1854 disable procedure call checks for toplevel
1855 bindings
1856 -strict-types assume variable do not change their type
1857 -clustering combine groups of local procedures into dispatch
1858 loop
1859 -lfa2 perform additional lightweight flow-analysis pass
1860 -unroll-limit LIMIT specifies inlining limit for self-recursive calls
1861
1862 Configuration options:
1863
1864 -unit NAME compile file as a library unit
1865 -uses NAME declare library unit as used.
1866 -heap-size NUMBER specifies heap-size of compiled executable
1867 -nursery NUMBER -stack-size NUMBER
1868 specifies nursery size of compiled executable
1869 -extend FILENAME load file before compilation commences
1870 -prelude EXPRESSION add expression to front of source file
1871 -postlude EXPRESSION add expression to end of source file
1872 -prologue FILENAME include file before main source file
1873 -epilogue FILENAME include file after main source file
1874 -dynamic compile as dynamically loadable code
1875 -require-extension NAME require and import extension NAME
1876
1877 Obscure options:
1878
1879 -debug MODES display debugging output for the given modes
1880 -raw do not generate implicit init- and exit code
1881 -emit-external-prototypes-first
1882 emit prototypes for callbacks before foreign
1883 declarations
1884 -regenerate-import-libraries emit import libraries even when unchanged
1885 -ignore-repository do not refer to repository for extensions
1886 -setup-mode prefer the current directory when locating extensions
1887
1888EOF
1889) )
1890
1891;; Same as above
1892(define (print-debug-options)
1893 (display #<<EOF
1894
1895Available debugging options:
1896
1897 a show node-matching during simplification
1898 b show breakdown of time needed for each compiler pass
1899 c print every expression before macro-expansion
1900 d lists all assigned global variables
1901 e show information about specializations
1902 h you already figured that out
1903 i show information about inlining
1904 m show GC statistics during compilation
1905 n print the line-number database
1906 o show performed optimizations
1907 p display information about what the compiler is currently doing
1908 r show invocation parameters
1909 s show program-size information and other statistics
1910 t show time needed for compilation
1911 u lists all unassigned global variable references
1912 x display information about experimental features
1913 D when printing nodes, use node-tree output
1914 I show inferred type information for unexported globals
1915 N show the real-name mapping table
1916 P show expressions after specialization
1917 S show applications of compiler syntax
1918 T show expressions after converting to node tree
1919 1 show source expressions
1920 2 show canonicalized expressions
1921 3 show expressions converted into CPS
1922 4 show database after each analysis pass
1923 5 show expressions after each optimization pass
1924 6 show expressions after each inlining pass
1925 7 show expressions after complete optimization
1926 8 show database after final analysis
1927 9 show expressions after closure conversion
1928
1929
1930EOF
1931))
1932)