~ chicken-core (master) /batch-driver.scm
Trap1;;;; batch-driver.scm - Driver procedure for the 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
29 (unit batch-driver)
30 (uses extras data-structures pathname expand
31 support compiler-syntax compiler optimizer internal
32 ;; TODO: Backend should be configurable
33 scrutinizer lfa2 c-platform c-backend user-pass))
34
35(module chicken.compiler.batch-driver
36 (compile-source-file)
37
38(import scheme
39 chicken.base
40 chicken.file
41 chicken.fixnum
42 chicken.format
43 chicken.gc
44 chicken.internal
45 chicken.load
46 chicken.pathname
47 chicken.platform
48 chicken.pretty-print
49 chicken.process-context
50 chicken.process-context.posix
51 chicken.string
52 chicken.syntax
53 chicken.port
54 chicken.time
55 chicken.condition
56 chicken.compiler.support
57 chicken.compiler.compiler-syntax
58 chicken.compiler.core
59 chicken.compiler.optimizer
60 chicken.compiler.scrutinizer
61 chicken.compiler.lfa2
62 chicken.compiler.c-platform
63 chicken.compiler.c-backend
64 chicken.compiler.user-pass)
65
66(include "tweaks")
67(include "mini-srfi-1.scm")
68
69(define-constant funny-message-timeout 60000)
70
71;;; Emit collected information from various statistics about the program
72
73(define (print-program-statistics db)
74 (receive
75 (size osize kvars kprocs globs sites entries) (compute-database-statistics db)
76 (when (debugging 's "program statistics:")
77 (printf "; program size: \t~s \toriginal program size: \t~s\n" size osize)
78 (printf "; variables with known values: \t~s\n" kvars)
79 (printf "; known procedures: \t~s\n" kprocs)
80 (printf "; global variables: \t~s\n" globs)
81 (printf "; known call sites: \t~s\n" sites)
82 (printf "; database entries: \t~s\n" entries) ) ) )
83
84;;; Initialize analysis database:
85;;
86;; - Simply marks the symbols directly in the plist.
87;; - Does nothing after the first invocation, but we leave it this way to
88;; have the option to add default entries for each new db.
89
90(define initialize-analysis-database
91 (let ((initial #t))
92 (lambda ()
93 (when initial
94 (for-each
95 (lambda (s)
96 (mark-variable s '##compiler#intrinsic 'standard))
97 standard-bindings)
98 (for-each
99 (lambda (s)
100 (mark-variable s '##compiler#intrinsic 'extended))
101 extended-bindings)
102 (for-each
103 (lambda (s)
104 (mark-variable s '##compiler#intrinsic 'internal))
105 internal-bindings))
106 (set! initial #f))))
107
108;;; Display analysis database:
109
110(define display-analysis-database
111 (let ((names '((captured . cpt) (assigned . set) (boxed . box) (global . glo)
112 (assigned-locally . stl)
113 (contractable . con) (standard-binding . stb) (simple . sim)
114 (inlinable . inl)
115 (collapsable . col) (removable . rem) (constant . con)
116 (inline-target . ilt) (inline-transient . itr)
117 (undefined . und) (replacing . rpg) (unused . uud) (extended-binding . xtb)
118 (inline-export . ilx) (hidden-refs . hrf)
119 (value-ref . vvf)
120 (customizable . cst) (has-unused-parameters . hup) (boxed-rest . bxr)
121 (shareable-container . shc) (shareable-user . shu) ) )
122 (omit #f))
123 (lambda (db)
124 (unless omit
125 (set! omit
126 (append default-standard-bindings
127 default-extended-bindings
128 internal-bindings) ) )
129 (hash-table-for-each
130 (lambda (sym plist)
131 (let ((val #f)
132 (lval #f)
133 (pvals #f)
134 (csites '())
135 (refs '())
136 (derived-rvars '()))
137 (unless (memq sym omit)
138 (write sym)
139 (let loop ((es plist))
140 (if (pair? es)
141 (begin
142 (case (caar es)
143 ((captured assigned boxed global contractable standard-binding assigned-locally
144 collapsable removable undefined replacing unused simple inlinable inline-export
145 has-unused-parameters extended-binding customizable constant boxed-rest hidden-refs
146 shareable-container shareable-user)
147 (printf "\t~a" (cdr (assq (caar es) names))) )
148 ((unknown)
149 (set! val 'unknown) )
150 ((value)
151 (unless (eq? val 'unknown) (set! val (cdar es))) )
152 ((local-value)
153 (unless (eq? val 'unknown) (set! lval (cdar es))) )
154 ((potential-values)
155 (set! pvals (cdar es)))
156 ((replacable home contains contained-in use-expr closure-size rest-parameter
157 captured-variables explicit-rest rest-cdr rest-null? consed-rest-arg
158 shared-closure sharing-mode)
159 (printf "\t~a=~s" (caar es) (cdar es)) )
160 ((derived-rest-vars)
161 (set! derived-rvars (cdar es)))
162 ((references)
163 (set! refs (cdar es)) )
164 ((call-sites)
165 (set! csites (cdar es)) )
166 (else (bomb "Illegal property" (car es))) )
167 (loop (cdr es)) ) ) )
168 (when (pair? refs) (printf "\trefs=~s" (length refs)))
169 (when (pair? derived-rvars) (printf "\tdrvars=~s" (length derived-rvars)))
170 (when (pair? csites) (printf "\tcss=~s" (length csites)))
171 (cond [(and val (not (eq? val 'unknown)))
172 (printf "\tval=~s" (cons (node-class val) (node-parameters val))) ]
173 [(and lval (not (eq? val 'unknown)))
174 (printf "\tlval=~s" (cons (node-class lval) (node-parameters lval)))])
175 (when (pair? pvals)
176 (for-each
177 (lambda (pval)
178 (printf "\tpval=~s" (cons (node-class pval) (node-parameters pval))))
179 pvals))
180 (newline) ) ) )
181 db) ) ) )
182
183;;; Compile a complete source file:
184
185(define (compile-source-file filename user-supplied-options . options)
186 (define (option-arg p)
187 (if (null? (cdr p))
188 (quit-compiling "missing argument to `-~A' option" (car p))
189 (let ([arg (cadr p)])
190 (if (symbol? arg)
191 (quit-compiling "invalid argument to `~A' option" arg)
192 arg) ) ) )
193 (initialize-compiler)
194 (set! explicit-use-flag (memq 'explicit-use options))
195 (set! emit-debug-info (memq 'debug-info options))
196 (when (memq 'module-registration options)
197 (set! compile-module-registration 'yes))
198 (when (memq 'no-module-registration options)
199 (set! compile-module-registration 'no))
200 (when (memq 'static options)
201 (set! static-extensions #t)
202 (register-feature! 'chicken-compile-static))
203 (let* ((dynamic (memq 'dynamic options))
204 (unit (memq 'unit options))
205 (init-forms `((##core#declare
206 ,@(append
207 default-declarations
208 (if emit-debug-info
209 '((uses debugger-client))
210 '())
211 (if explicit-use-flag
212 '()
213 `((uses ,@default-units)))
214 (if (and static-extensions
215 (not dynamic)
216 (not unit)
217 (not explicit-use-flag)
218 (or (not compile-module-registration)
219 (eq? compile-module-registration 'yes)))
220 '((uses eval-modules))
221 '())))))
222 (import-forms `((import-for-syntax ,@default-syntax-imports)
223 ,@(if explicit-use-flag
224 '()
225 `((import-syntax ,@default-imports)))))
226 (cleanup-forms '(((chicken.base#implicit-exit-handler))))
227 (outfile (cond ((memq 'output-file options)
228 => (lambda (node)
229 (let ((oname (option-arg node)))
230 (if (symbol? oname)
231 (symbol->string oname)
232 oname) ) ) )
233 ((memq 'to-stdout options) #f)
234 (else (make-pathname #f (if filename (pathname-file filename) "out") "c")) ) )
235 ;; Create a temporary file to receive the C code, so that it
236 ;; can atomically be renamed to the actual output file after
237 ;; the C generation.
238 (tmp-outfile (and outfile
239 (conc outfile ".tmp." (current-process-id) (current-seconds))))
240 (opasses (default-optimization-passes))
241 (time0 #f)
242 (time-breakdown #f)
243 (forms '())
244 (inline-output-file #f)
245 (profile (or (memq 'profile options)
246 (memq 'accumulate-profile options)
247 (memq 'profile-name options)))
248 (profile-name
249 (and-let* ((pn (memq 'profile-name options))) (cadr pn)))
250 (hsize (memq 'heap-size options))
251 (kwstyle (memq 'keyword-style options))
252 (a-only (memq 'analyze-only options))
253 (do-scrutinize #t)
254 (do-lfa2 (memq 'lfa2 options))
255 (dumpnodes #f)
256 (start-time #f)
257 (upap #f)
258 (ssize (or (memq 'nursery options) (memq 'stack-size options)))
259 (module-name
260 (and-let* ((m (memq 'module options)))
261 (option-arg m))))
262
263 (define (cputime) (current-process-milliseconds))
264
265 (define (dribble fstr . args)
266 (debugging 'p (apply sprintf fstr args)))
267
268 (define (print-header mode dbgmode)
269 (debugging 'p "pass" mode)
270 (and (memq dbgmode debugging-chicken)
271 (begin
272 (printf "[~a]~%" mode)
273 #t) ) )
274
275 (define (print-node mode dbgmode n)
276 (when (print-header mode dbgmode)
277 (if dumpnodes
278 (dump-nodes n)
279 (pretty-print (build-expression-tree n)) ) ) )
280
281 (define (print-db mode dbgmode db pass)
282 (when (print-header mode dbgmode)
283 (printf "(iteration ~s)~%" pass)
284 (display-analysis-database db) ) )
285
286 (define (print-expr mode dbgmode xs)
287 (when (print-header mode dbgmode)
288 (for-each
289 (lambda (x)
290 (pretty-print x)
291 (newline))
292 xs) ) )
293
294 (define (string-trim str)
295 (let loop ((front 0)
296 (back (string-length str)))
297 (cond ((= front back) "")
298 ((char-whitespace? (string-ref str front))
299 (loop (add1 front) back))
300 ((char-whitespace? (string-ref str (sub1 back)))
301 (loop front (sub1 back)))
302 (else (substring str front back)))))
303
304 (define (string->extension-name str)
305 (let ((str (string-trim str)))
306 (if (and (positive? (string-length str))
307 (char=? #\( (string-ref str 0)))
308 (handle-exceptions ex
309 (##sys#error "invalid import specification" str)
310 (with-input-from-string str read))
311 (string->symbol str))))
312
313 (define (arg-val str)
314 (let* ((len (string-length str))
315 (len1 (- len 1)) )
316 (or (if (< len 2)
317 (string->number str)
318 (case (string-ref str len1)
319 ((#\m #\M) (* (string->number (substring str 0 len1)) (* 1024 1024)))
320 ((#\k #\K) (* (string->number (substring str 0 len1)) 1024))
321 (else (string->number str)) ) )
322 (quit-compiling "invalid numeric argument ~S" str) ) ) )
323
324 (define (collect-options opt)
325 (let loop ([opts options])
326 (cond [(memq opt opts) => (lambda (p) (cons (option-arg p) (loop (cddr p))))]
327 [else '()] ) ) )
328
329 (define (begin-time)
330 (when time-breakdown (set! time0 (cputime))) )
331
332 (define (end-time pass)
333 (when time-breakdown
334 (printf "milliseconds needed for ~a: \t~s~%"
335 pass
336 (inexact->exact (round (- (cputime) time0)) ) )))
337
338 (define (analyze pass node . args)
339 (let-optionals args ((no 0) (contf #t))
340 (let ((db (analyze-expression node)))
341 (when upap
342 (upap pass db node
343 (cut db-get db <> <>)
344 (cut db-put! db <> <> <>)
345 no contf) )
346 db) ) )
347
348 (define (chop-separator str)
349 (let ((len (sub1 (string-length str))))
350 (if (and (> len 0)
351 (memq (string-ref str len) '(#\\ #\/)))
352 (substring str 0 len)
353 str) ) )
354
355 (when unit
356 (set! unit-name (string->symbol (option-arg unit))))
357 (when (or unit-name dynamic)
358 (set! standalone-executable #f))
359 (when (memq 'ignore-repository options)
360 (set! ##sys#dload-disabled #t)
361 (repository-path #f))
362 (set! enable-specialization (memq 'specialize options))
363 (set! debugging-chicken
364 (append-map
365 (lambda (do)
366 (map (lambda (c) (string->symbol (string c)))
367 (string->list do) ) )
368 (collect-options 'debug) ) )
369 (when (memq 'h debugging-chicken)
370 (print-debug-options)
371 (exit))
372 (set! dumpnodes (memq '|D| debugging-chicken))
373 (set! import-libraries
374 (map (lambda (il)
375 (cons (string->symbol il)
376 (string-append il ".import.scm")))
377 (collect-options 'emit-import-library)))
378 (when (and (memq 'emit-all-import-libraries options)
379 (not a-only))
380 (set! all-import-libraries #t))
381 (when enable-specialization
382 (set! do-scrutinize #t))
383 (when (memq 't debugging-chicken) (##sys#start-timer))
384 (when (memq 'b debugging-chicken) (set! time-breakdown #t))
385 (when (memq 'raw options)
386 (set! explicit-use-flag #t)
387 (set! init-forms '())
388 (set! import-forms '())
389 (set! cleanup-forms '()))
390 (when (memq 'no-lambda-info options)
391 (set! emit-closure-info #f) )
392 (when (memq 'no-compiler-syntax options)
393 (set! compiler-syntax-enabled #f))
394 (when (memq 'local options)
395 (set! local-definitions #t))
396 (when (memq 'inline-global options)
397 (set! enable-inline-files #t)
398 (set! inline-locally #t))
399 (when (memq 'verbose options)
400 (set! verbose-mode #t)
401 (set! ##sys#notices-enabled #t))
402 (when (memq 'strict-types options)
403 (set! strict-variable-types #t)
404 (set! enable-specialization #t))
405 (when (memq 'no-warnings options)
406 (dribble "Warnings are disabled")
407 (set! ##sys#warnings-enabled #f)
408 (set! do-scrutinize #f)) ; saves some processing time
409 (when (memq 'optimize-leaf-routines options) (set! optimize-leaf-routines #t))
410 (when (memq 'unsafe options)
411 (set! unsafe #t) )
412 (when (memq 'setup-mode options)
413 (set! ##sys#setup-mode #t))
414 (when (memq 'regenerate-import-libraries options)
415 (set! preserve-unchanged-import-libraries #f))
416 (when (memq 'disable-interrupts options) (set! insert-timer-checks #f))
417 (when (memq 'fixnum-arithmetic options) (set! number-type 'fixnum))
418 (when (memq 'block options) (set! block-compilation #t))
419 (when (memq 'emit-external-prototypes-first options)
420 (set! external-protos-first #t))
421 (when (memq 'inline options) (set! inline-locally #t))
422 (and-let* ((elf (memq 'emit-link-file options)))
423 (set! emit-link-file (option-arg elf)))
424 (and-let* ((ifile (memq 'emit-inline-file options)))
425 (set! inline-locally #t) ; otherwise this option makes no sense
426 (set! local-definitions #t)
427 (set! inline-output-file (option-arg ifile)))
428 (and-let* ((tfile (memq 'emit-types-file options)))
429 (set! types-output-file (option-arg tfile)))
430 (and-let* ([inlimit (memq 'inline-limit options)])
431 (set! inline-max-size
432 (let ([arg (option-arg inlimit)])
433 (or (string->number arg)
434 (quit-compiling
435 "invalid argument to `-inline-limit' option: `~A'" arg) ) ) ) )
436 (and-let* ((ulimit (memq 'unroll-limit options)))
437 (set! unroll-limit
438 (let ((arg (option-arg ulimit)))
439 (or (string->number arg)
440 (quit-compiling
441 "invalid argument to `-unroll-limit' option: `~A'" arg) ) ) ) )
442 (when (memq 'case-insensitive options)
443 (dribble "Identifiers and symbols are case insensitive")
444 (register-feature! 'case-insensitive)
445 (case-sensitive #f) )
446 (when kwstyle
447 (let ([val (option-arg kwstyle)])
448 (cond [(string=? "prefix" val) (keyword-style #:prefix)]
449 [(string=? "none" val) (keyword-style #:none)]
450 [(string=? "suffix" val) (keyword-style #:suffix)]
451 [else (quit-compiling
452 "invalid argument to `-keyword-style' option")] ) ) )
453 (when (memq 'no-parentheses-synonyms options)
454 (dribble "Disabled support for parentheses synonyms")
455 (parentheses-synonyms #f) )
456 (when (memq 'r7rs-syntax options)
457 (dribble "Disabled the CHICKEN extensions to R7RS syntax")
458 (case-sensitive #f)
459 (keyword-style #:none)
460 (parentheses-synonyms #f))
461 (set! ##sys#read-error-with-line-number #t)
462 (set! ##sys#include-pathnames
463 (append (map chop-separator (collect-options 'include-path))
464 ##sys#include-pathnames) )
465 (when (and outfile filename (string=? outfile filename))
466 (quit-compiling "source- and output-filename are the same") )
467 (when (memq 'keep-shadowed-macros options)
468 (set! undefine-shadowed-macros #f) )
469 (when (memq 'no-argc-checks options)
470 (set! no-argc-checks #t) )
471 (when (memq 'no-bound-checks options)
472 (set! no-bound-checks #t) )
473 (when (memq 'no-procedure-checks options)
474 (set! no-procedure-checks #t) )
475 (when (memq 'no-procedure-checks-for-toplevel-bindings options)
476 (set! no-global-procedure-checks #t) )
477 (when (memq 'no-procedure-checks-for-usual-bindings options)
478 (for-each
479 (lambda (v)
480 (mark-variable v '##compiler#always-bound-to-procedure)
481 (mark-variable v '##compiler#always-bound) )
482 default-standard-bindings)
483 (for-each
484 (lambda (v)
485 (mark-variable v '##compiler#always-bound-to-procedure)
486 (mark-variable v '##compiler#always-bound) )
487 default-extended-bindings) )
488 (when (memq 'p debugging-chicken) (load-verbose #t))
489
490 ;; Handle feature options:
491 (for-each
492 register-feature!
493 (append-map (cut string-split <> ", ") (collect-options 'feature)))
494 (for-each
495 unregister-feature!
496 (append-map (cut string-split <> ",") (collect-options 'no-feature)))
497
498 ;; Load extensions:
499 (set! ##sys#features (cons #:compiler-extension ##sys#features))
500 (let ([extends (collect-options 'extend)])
501 (dribble "Loading compiler extensions...")
502 (for-each
503 (lambda (e)
504 (let ((f (##sys#resolve-include-filename e #f #t #f)))
505 (when (not f) (quit-compiling "cannot load extension: ~a" e))
506 (load f)))
507 extends) )
508 (set! ##sys#features (delete #:compiler-extension ##sys#features eq?))
509 (set! ##sys#features (cons '#:compiling ##sys#features))
510 (set! upap (user-post-analysis-pass))
511
512 ;; Handle units added with the "-uses" flag.
513 (let ((uses (append-map
514 (lambda (u) (map string->symbol (string-split u ", ")))
515 (collect-options 'uses))))
516 (unless (null? uses)
517 (set! init-forms
518 (append init-forms `((##core#declare (uses . ,uses)))))))
519
520 ;; Mark linked libraries so they will be compiled as unit dependencies.
521 (let ((link (append-map
522 (lambda (l) (map string->symbol (string-split l ", ")))
523 (collect-options 'link))))
524 (set! linked-libraries (lset-union/eq? linked-libraries link)))
525
526 ;; Append required extensions to imports:
527 (set! import-forms
528 (append
529 import-forms
530 (map (lambda (r) `(import ,(string->extension-name r)))
531 (collect-options 'require-extension))))
532
533 (when (memq 'compile-syntax options)
534 (set! ##sys#enable-runtime-macros #t) )
535 (set! target-heap-size
536 (and hsize
537 (arg-val (option-arg hsize))))
538 (set! target-stack-size
539 (and ssize
540 (arg-val (option-arg ssize))))
541 (set! emit-trace-info (not (memq 'no-trace options)))
542 (set! disable-stack-overflow-checking (memq 'disable-stack-overflow-checks options))
543 (set! bootstrap-mode (feature? #:chicken-bootstrap))
544 (when (memq 'm debugging-chicken) (set-gc-report! #t))
545 (cond ((memq 'no-usual-integrations options)
546 (set! do-scrutinize #f))
547 (else
548 (set! standard-bindings default-standard-bindings)
549 (set! extended-bindings default-extended-bindings) ))
550 (dribble "debugging info: ~A"
551 (if emit-trace-info
552 "calltrace"
553 "none") )
554 (when profile
555 (let ((acc (eq? 'accumulate-profile (car profile))))
556 (when (and acc (not profile-name))
557 (quit-compiling
558 "you need to specify -profile-name if using accumulated profiling runs"))
559 (set! emit-profile #t)
560 (set! profiled-procedures 'all)
561 (set! init-forms
562 (append
563 init-forms
564 default-profiling-declarations
565 (if acc
566 '((set! ##sys#profile-append-mode #t))
567 '() ) ) )
568 (dribble "generating ~aprofiled code" (if acc "accumulative " "")) ))
569
570 ;;XXX hardcoded "modules.db" is bad (also used in chicken-install.scm)
571 (load-identifier-database "modules.db")
572
573 (cond ((memq 'version options)
574 (print-version #t)
575 (newline) )
576 ((or (memq 'help options) (memq '-help options) (memq 'h options) (memq '-h options))
577 (print-usage))
578 ((memq 'release options)
579 (display (chicken-version))
580 (newline) )
581 ((not filename)
582 (print-version #t)
583 (display "\nEnter `chicken -help' for information on how to use the compiler,\n")
584 (display "or try `csc' for a more convenient interface.\n")
585 (display "\nRun `csi' to start the interactive interpreter.\n"))
586 (else
587
588 ;; Display header:
589 (dribble "compiling `~a' ..." filename)
590 (debugging 'r "options" options)
591 (debugging 'r "debugging options" debugging-chicken)
592 (debugging 'r "target heap size" target-heap-size)
593 (debugging 'r "target stack size" target-stack-size)
594 (set! start-time (cputime))
595
596 ;; Read toplevel expressions:
597 (set! ##sys#line-number-database (make-vector line-number-database-size '()))
598 (let ([prelude (collect-options 'prelude)]
599 [postlude (collect-options 'postlude)]
600 [files (append
601 (collect-options 'prologue)
602 (list filename)
603 (collect-options 'epilogue) ) ] )
604
605 (let ([proc (user-read-pass)])
606 (cond [proc
607 (dribble "User read pass...")
608 (set! forms (proc prelude files postlude)) ]
609 [else
610 (do ([files files (cdr files)])
611 ((null? files)
612 (set! forms
613 (append (map string->expr prelude)
614 (reverse forms)
615 (map string->expr postlude) ) ) )
616 (let* ((f (car files))
617 (in (check-and-open-input-file f)) )
618 (fluid-let ((##sys#current-source-filename f))
619 (let loop ()
620 (let ((x (chicken.syntax#read-with-source-info in))) ; OBSOLETE - after bootstrapping we can get rid of this explicit namespacing
621
622 (cond ((eof-object? x)
623 (close-checked-input-file in f) )
624 (else
625 (set! forms (cons x forms))
626 (loop)))))))) ] ) ) )
627
628 ;; Start compilation passes:
629 (let ([proc (user-preprocessor-pass)])
630 (when proc
631 (dribble "User preprocessing pass...")
632 (set! forms (map proc forms))))
633
634 (print-expr "source" '|1| forms)
635 (begin-time)
636 ;; Canonicalize s-expressions
637 (let* ((init0 (map canonicalize-expression init-forms))
638 (exps0 (map (lambda (x)
639 (fluid-let ((##sys#current-source-filename filename))
640 (canonicalize-expression x)))
641 (let ((forms (append import-forms forms)))
642 (if (not module-name)
643 forms
644 `((##core#module
645 ,(string->symbol module-name) ()
646 ,@forms))))))
647 (uses0 (map (lambda (u)
648 (canonicalize-expression `(##core#require ,u)))
649 (##sys#fast-reverse used-libraries)))
650 (exps (append
651 (map (lambda (ic) `(set! ,(cdr ic) ',(car ic))) immutable-constants)
652 init0
653 uses0
654 (if unit-name `((##core#provide ,unit-name)) '())
655 (if emit-profile
656 (profiling-prelude-exps (and (not unit-name)
657 (or profile-name #t)))
658 '() )
659 exps0
660 (if standalone-executable
661 cleanup-forms
662 '((##core#undefined))))))
663
664 (unless (null? import-libraries)
665 (quit-compiling
666 "No module definition found for import libraries to emit: ~A"
667 ;; ~S would be confusing: separate with a comma
668 (string-intersperse
669 (map (lambda (il) (->string (car il)))
670 import-libraries) ", ")))
671
672 (when (pair? compiler-syntax-statistics)
673 (with-debugging-output
674 'S
675 (lambda ()
676 (print "applied compiler syntax:")
677 (for-each
678 (lambda (cs) (printf " ~a\t\t~a~%" (car cs) (cdr cs)))
679 compiler-syntax-statistics))))
680 (when (debugging '|N| "real name table:")
681 (display-real-name-table) )
682 (when (debugging 'n "line number database:")
683 (##sys#display-line-number-database) )
684
685 (set! ##sys#line-number-database line-number-database-2)
686 (set! line-number-database-2 #f)
687
688 (end-time "canonicalization")
689 (print-expr "canonicalized" '|2| exps)
690
691 (when (memq 'check-syntax options) (exit))
692
693 ;; User-defined pass (s-expressions)
694 (let ([proc (user-pass)])
695 (when proc
696 (dribble "User pass...")
697 (begin-time)
698 (set! exps (map proc exps))
699 (end-time "user pass") ) )
700
701 ;; Convert s-expressions to node tree
702 (let ((node0 (build-toplevel-procedure
703 (build-node-graph
704 (canonicalize-begin-body exps))))
705 (db #f))
706 (print-node "initial node tree" '|T| node0)
707 (initialize-analysis-database)
708
709 ;; collect requirements and load inline files
710 (let ((extensions required-extensions))
711 (when enable-inline-files
712 (for-each
713 (lambda (id)
714 (and-let* ((ifile (##sys#resolve-include-filename
715 (symbol->string id) '(".inline") #t #f)))
716 (dribble "Loading inline file ~a ..." ifile)
717 (load-inline-file ifile)))
718 extensions))
719 (let ((ifs (collect-options 'consult-inline-file)))
720 (unless (null? ifs)
721 (set! inline-locally #t)
722 (for-each
723 (lambda (ilf)
724 (dribble "Loading inline file ~a ..." ilf)
725 (load-inline-file ilf) )
726 ifs)))
727 ;; Perform scrutiny and optionally specialization
728 (when (or do-scrutinize enable-specialization)
729 ;;XXX hardcoded database file name
730 (unless (memq 'ignore-repository options)
731 (unless (load-type-database "types.db"
732 enable-specialization)
733 (quit-compiling
734 "default type-database `types.db' not found")))
735 (for-each
736 (lambda (fn)
737 (or (load-type-database fn enable-specialization #f)
738 (quit-compiling "type-database `~a' not found" fn)))
739 (collect-options 'consult-types-file))
740 (for-each
741 (lambda (id)
742 (load-type-database
743 (make-pathname #f (symbol->string id) "types")
744 enable-specialization))
745 extensions)
746 (begin-time)
747 (set! first-analysis #f)
748 (set! db (analyze 'scrutiny node0))
749 (print-db "analysis" '|0| db 0)
750 (end-time "pre-analysis (scrutiny)")
751 (begin-time)
752 (debugging 'p "performing scrutiny")
753 (scrutinize node0 db
754 do-scrutinize enable-specialization
755 strict-variable-types block-compilation)
756 (end-time "scrutiny")
757 (when enable-specialization
758 (print-node "specialization" '|P| node0))
759 (set! first-analysis #t) ) )
760
761 ;; TODO: Move this so that we don't need to export these
762 (set! ##sys#line-number-database #f)
763 (set! constant-table #f)
764 (set! inline-table #f)
765 ;; Analyze toplevel assignments
766 (unless unsafe
767 (scan-toplevel-assignments (first (node-subexpressions node0))) )
768
769 (begin-time)
770 ;; Convert to CPS
771 (let ([node1 (perform-cps-conversion node0)])
772 (end-time "cps conversion")
773 (print-node "cps" '|3| node1)
774
775 ;; Optimization loop:
776 (let loop ((i 1)
777 (node2 node1)
778 (progress #t))
779 (begin-time)
780 ;; Analyze node tree for optimization
781 (let ([db (analyze 'opt node2 i progress)])
782 (when first-analysis
783 (when (memq 'u debugging-chicken)
784 (dump-undefined-globals db))
785 (when (memq 'd debugging-chicken)
786 (dump-defined-globals db))
787 (when (memq 'v debugging-chicken)
788 (dump-global-refs db))
789 ;; do this here, because we must make sure we have a db
790 (and-let* ((tfile (or (and (eq? types-output-file #t)
791 (pathname-replace-extension filename "types"))
792 (and (string? types-output-file)
793 types-output-file))))
794 (dribble "generating type file `~a' ..." tfile)
795 (emit-types-file filename tfile db block-compilation)))
796 (set! first-analysis #f)
797 (end-time "analysis")
798 (print-db "analysis" '|4| db i)
799
800 (when (memq 's debugging-chicken)
801 (print-program-statistics db))
802
803 ;; Optimize (once)
804 (cond (progress
805 (debugging 'p "optimization pass" i)
806 (begin-time)
807 (receive (node2 progress-flag)
808 (perform-high-level-optimizations
809 node2 db block-compilation
810 inline-locally inline-max-size
811 unroll-limit
812 inline-substitutions-enabled)
813 (end-time "optimization")
814 (print-node "optimized-iteration" '|5| node2)
815 (cond (progress-flag
816 (loop (add1 i) node2 #t))
817 ((not inline-substitutions-enabled)
818 (debugging 'p "rewritings enabled")
819 (set! inline-substitutions-enabled #t)
820 (loop (add1 i) node2 #t) )
821 (optimize-leaf-routines
822 (begin-time)
823 (let ([db (analyze 'leaf node2)])
824 (end-time "analysis")
825 (begin-time)
826 (let ((progress
827 (transform-direct-lambdas! node2 db)))
828 (end-time "leaf routine optimization")
829 (loop (add1 i)
830 node2
831 progress) ) ) )
832 (else
833 (loop (add1 i) node2 #f)) ) ) )
834
835 (else
836 ;; Secondary flow-analysis
837 (when do-lfa2
838 (begin-time)
839 (debugging 'p "doing lfa2")
840 (let ((floatvars (perform-secondary-flow-analysis node2 db)))
841 (end-time "secondary flow analysis")
842 (unless (null? floatvars)
843 (begin-time)
844 (debugging 'p "doing unboxing")
845 (set! node2 (perform-unboxing node2 floatvars)))
846 (end-time "unboxing")))
847 (print-node "optimized" '|7| node2)
848 ;; inlining into a file with interrupts enabled would
849 ;; change semantics
850 (when (and inline-output-file insert-timer-checks)
851 (let ((f inline-output-file))
852 (dribble "generating global inline file `~a' ..." f)
853 (emit-global-inline-file
854 filename f db block-compilation
855 inline-max-size
856 (map foreign-stub-id foreign-lambda-stubs)) ) )
857 (begin-time)
858 ;; Closure conversion
859 (set! node2 (perform-closure-conversion node2 db))
860 (end-time "closure conversion")
861 (print-db "final-analysis" '|8| db i)
862 (when (and ##sys#warnings-enabled
863 (> (- (cputime) start-time) funny-message-timeout))
864 (display "(don't worry - still compiling...)\n") )
865 (print-node "closure-converted" '|9| node2)
866 (when a-only (exit 0))
867 (begin-time)
868 ;; Preparation
869 (receive (node literals lliterals lambda-table dbg-info)
870 (prepare-for-code-generation node2 db)
871 (end-time "preparation")
872 (begin-time)
873
874 ;; generate link file
875 (when emit-link-file
876 (let ((exts required-extensions))
877 (dribble "generating link file `~a' ..." emit-link-file)
878 (with-output-to-file emit-link-file (cut pp exts))))
879
880 ;; Code generation
881 (let ((out (if tmp-outfile
882 (open-output-file tmp-outfile)
883 (current-output-port))) )
884 (when tmp-outfile
885 (dribble "generating `~A' ..." tmp-outfile))
886 (generate-code literals lliterals lambda-table out filename
887 user-supplied-options dynamic db dbg-info)
888 (when tmp-outfile
889 (close-output-port out)
890 (rename-file tmp-outfile outfile #t)))
891 (end-time "code generation")
892 (when (memq 't debugging-chicken)
893 (##sys#display-times (##sys#stop-timer)))
894 (compiler-cleanup-hook)
895 (dribble "compilation finished.") ) ) ) ) ) ) ) ) ) ) ) )
896)