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