~ chicken-core (master) /batch-driver.scm


  1;;;; 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 'merge-reusable-closures options)
406      (set! merge-reusable-closures #t))
407    (when (memq 'merge-shareable-closures options)
408      (set! merge-shareable-closures #t))
409    (when (memq 'no-warnings options)
410      (dribble "Warnings are disabled")
411      (set! ##sys#warnings-enabled #f)
412      (set! do-scrutinize #f))		; saves some processing time
413    (when (memq 'optimize-leaf-routines options) (set! optimize-leaf-routines #t))
414    (when (memq 'unsafe options)
415      (set! unsafe #t) )
416    (when (memq 'setup-mode options)
417      (set! ##sys#setup-mode #t))
418    (when (memq 'regenerate-import-libraries options)
419      (set! preserve-unchanged-import-libraries #f))
420    (when (memq 'disable-interrupts options) (set! insert-timer-checks #f))
421    (when (memq 'fixnum-arithmetic options) (set! number-type 'fixnum))
422    (when (memq 'block options) (set! block-compilation #t))
423    (when (memq 'emit-external-prototypes-first options)
424      (set! external-protos-first #t))
425    (when (memq 'inline options) (set! inline-locally #t))
426    (and-let* ((elf (memq 'emit-link-file options)))
427      (set! emit-link-file (option-arg elf)))
428    (and-let* ((ifile (memq 'emit-inline-file options)))
429      (set! inline-locally #t)		; otherwise this option makes no sense
430      (set! local-definitions #t)
431      (set! inline-output-file (option-arg ifile)))
432    (and-let* ((tfile (memq 'emit-types-file options)))
433      (set! types-output-file (option-arg tfile)))
434    (and-let* ([inlimit (memq 'inline-limit options)])
435      (set! inline-max-size
436	(let ([arg (option-arg inlimit)])
437	  (or (string->number arg)
438	      (quit-compiling
439	       "invalid argument to `-inline-limit' option: `~A'" arg) ) ) ) )
440    (and-let* ((ulimit (memq 'unroll-limit options)))
441      (set! unroll-limit
442	(let ((arg (option-arg ulimit)))
443	  (or (string->number arg)
444	      (quit-compiling
445	       "invalid argument to `-unroll-limit' option: `~A'" arg) ) ) ) )
446    (when (memq 'case-insensitive options)
447      (dribble "Identifiers and symbols are case insensitive")
448      (register-feature! 'case-insensitive)
449      (case-sensitive #f) )
450    (when kwstyle
451      (let ([val (option-arg kwstyle)])
452	(cond [(string=? "prefix" val) (keyword-style #:prefix)]
453	      [(string=? "none" val) (keyword-style #:none)]
454	      [(string=? "suffix" val) (keyword-style #:suffix)]
455	      [else (quit-compiling
456		     "invalid argument to `-keyword-style' option")] ) ) )
457    (when (memq 'no-parentheses-synonyms options)
458      (dribble "Disabled support for parentheses synonyms")
459      (parentheses-synonyms #f) )
460    (when (memq 'r7rs-syntax options)
461      (dribble "Disabled the CHICKEN extensions to R7RS syntax")
462      (case-sensitive #f)
463      (keyword-style #:none)
464      (parentheses-synonyms #f))
465    (set! ##sys#read-error-with-line-number #t)
466    (set! ##sys#include-pathnames
467      (append (map chop-separator (collect-options 'include-path))
468	      ##sys#include-pathnames) )
469    (when (and outfile filename (string=? outfile filename))
470      (quit-compiling "source- and output-filename are the same") )
471    (when (memq 'keep-shadowed-macros options)
472      (set! undefine-shadowed-macros #f) )
473    (when (memq 'no-argc-checks options)
474      (set! no-argc-checks #t) )
475    (when (memq 'no-bound-checks options)
476      (set! no-bound-checks #t) )
477    (when (memq 'no-procedure-checks options)
478      (set! no-procedure-checks #t) )
479    (when (memq 'no-procedure-checks-for-toplevel-bindings options)
480      (set! no-global-procedure-checks #t) )
481    (when (memq 'no-procedure-checks-for-usual-bindings options)
482      (for-each
483       (lambda (v)
484         (mark-variable v '##compiler#always-bound-to-procedure)
485         (mark-variable v '##compiler#always-bound) )
486       default-standard-bindings)
487      (for-each
488       (lambda (v)
489         (mark-variable v '##compiler#always-bound-to-procedure)
490         (mark-variable v '##compiler#always-bound) )
491       default-extended-bindings) )
492    (when (memq 'p debugging-chicken) (load-verbose #t))
493
494    ;; Handle feature options:
495    (for-each
496     register-feature!
497     (append-map (cut string-split <> ", ") (collect-options 'feature)))
498    (for-each
499     unregister-feature!
500     (append-map (cut string-split <> ",") (collect-options 'no-feature)))
501
502    ;; Load extensions:
503    (set! ##sys#features (cons #:compiler-extension ##sys#features))
504    (let ([extends (collect-options 'extend)])
505      (dribble "Loading compiler extensions...")
506      (for-each
507       (lambda (e)
508	 (let ((f (##sys#resolve-include-filename e #f #t #f)))
509	   (when (not f) (quit-compiling "cannot load extension: ~a" e))
510	   (load f)))
511       extends) )
512    (set! ##sys#features (delete #:compiler-extension ##sys#features eq?))
513    (set! ##sys#features (cons '#:compiling ##sys#features))
514    (set! upap (user-post-analysis-pass))
515
516    ;; Handle units added with the "-uses" flag.
517    (let ((uses (append-map
518		 (lambda (u) (map string->symbol (string-split u ", ")))
519		 (collect-options 'uses))))
520      (unless (null? uses)
521	(set! init-forms
522	  (append init-forms `((##core#declare (uses . ,uses)))))))
523
524    ;; Mark linked libraries so they will be compiled as unit dependencies.
525    (let ((link (append-map
526		 (lambda (l) (map string->symbol (string-split l ", ")))
527		 (collect-options 'link))))
528      (set! linked-libraries (lset-union/eq? linked-libraries link)))
529
530    ;; Append required extensions to imports:
531    (set! import-forms
532      (append
533       import-forms
534       (map (lambda (r) `(import ,(string->extension-name r)))
535	    (collect-options 'require-extension))))
536
537    (when (memq 'compile-syntax options)
538      (set! ##sys#enable-runtime-macros #t) )
539    (set! target-heap-size
540      (and hsize
541	   (arg-val (option-arg hsize))))
542    (set! target-stack-size
543      (and ssize
544	   (arg-val (option-arg ssize))))
545    (set! emit-trace-info (not (memq 'no-trace options)))
546    (set! disable-stack-overflow-checking (memq 'disable-stack-overflow-checks options))
547    (set! bootstrap-mode (feature? #:chicken-bootstrap))
548    (when (memq 'm debugging-chicken) (set-gc-report! #t))
549    (cond ((memq 'no-usual-integrations options)
550	   (set! do-scrutinize #f))
551	  (else
552	   (set! standard-bindings default-standard-bindings)
553	   (set! extended-bindings default-extended-bindings) ))
554    (dribble "debugging info: ~A"
555	     (if emit-trace-info
556		 "calltrace"
557		 "none") )
558    (when profile
559      (let ((acc (eq? 'accumulate-profile (car profile))))
560	(when (and acc (not profile-name))
561	  (quit-compiling
562	   "you need to specify -profile-name if using accumulated profiling runs"))
563	(set! emit-profile #t)
564	(set! profiled-procedures 'all)
565	(set! init-forms
566	  (append
567	   init-forms
568	   default-profiling-declarations
569	   (if acc
570	       '((set! ##sys#profile-append-mode #t))
571	       '() ) ) )
572	(dribble "generating ~aprofiled code" (if acc "accumulative " "")) ))
573
574    ;;XXX hardcoded "modules.db" is bad (also used in chicken-install.scm)
575    (load-identifier-database "modules.db")
576
577    (cond ((memq 'version options)
578	   (print-version #t)
579	   (newline) )
580	  ((or (memq 'help options) (memq '-help options) (memq 'h options) (memq '-h options))
581	   (print-usage))
582	  ((memq 'release options)
583	   (display (chicken-version))
584	   (newline) )
585	  ((not filename)
586	   (print-version #t)
587	   (display "\nEnter `chicken -help' for information on how to use the compiler,\n")
588	   (display "or try `csc' for a more convenient interface.\n")
589	   (display "\nRun `csi' to start the interactive interpreter.\n"))
590	  (else
591
592	   ;; Display header:
593	   (dribble "compiling `~a' ..." filename)
594	   (debugging 'r "options" options)
595	   (debugging 'r "debugging options" debugging-chicken)
596	   (debugging 'r "target heap size" target-heap-size)
597	   (debugging 'r "target stack size" target-stack-size)
598	   (set! start-time (cputime))
599
600	   ;; Read toplevel expressions:
601	   (set! ##sys#line-number-database (make-vector line-number-database-size '()))
602	   (let ([prelude (collect-options 'prelude)]
603		 [postlude (collect-options 'postlude)]
604		 [files (append
605			 (collect-options 'prologue)
606			 (list filename)
607			 (collect-options 'epilogue) ) ]  )
608
609	     (let ([proc (user-read-pass)])
610	       (cond [proc
611		      (dribble "User read pass...")
612		      (set! forms (proc prelude files postlude)) ]
613		     [else
614		      (do ([files files (cdr files)])
615			  ((null? files)
616			   (set! forms
617			     (append (map string->expr prelude)
618				     (reverse forms)
619				     (map string->expr postlude) ) ) )
620			(let* ((f (car files))
621			       (in (check-and-open-input-file f)) )
622			  (fluid-let ((##sys#current-source-filename f))
623			    (let loop ()
624			      (let ((x (chicken.syntax#read-with-source-info in))) ; OBSOLETE - after bootstrapping we can get rid of this explicit namespacing
625
626				(cond ((eof-object? x)
627				       (close-checked-input-file in f) )
628				      (else
629				       (set! forms (cons x forms))
630				       (loop)))))))) ] ) ) )
631
632	   ;; Start compilation passes:
633	   (let ([proc (user-preprocessor-pass)])
634	     (when proc
635	       (dribble "User preprocessing pass...")
636	       (set! forms (map proc forms))))
637
638	   (print-expr "source" '|1| forms)
639	   (begin-time)
640	   ;; Canonicalize s-expressions
641	   (let* ((init0 (map canonicalize-expression init-forms))
642		  (exps0 (map (lambda (x)
643				(fluid-let ((##sys#current-source-filename filename))
644				  (canonicalize-expression x)))
645			      (let ((forms (append import-forms forms)))
646				(if (not module-name)
647				    forms
648				    `((##core#module
649				       ,(string->symbol module-name) ()
650				       ,@forms))))))
651		  (uses0 (map (lambda (u)
652				(canonicalize-expression `(##core#require ,u)))
653			      (##sys#fast-reverse used-libraries)))
654		  (exps (append
655			 (map (lambda (ic) `(set! ,(cdr ic) ',(car ic))) immutable-constants)
656			 init0
657			 uses0
658			 (if unit-name `((##core#provide ,unit-name)) '())
659			 (if emit-profile
660			     (profiling-prelude-exps (and (not unit-name)
661							  (or profile-name #t)))
662			     '() )
663			 exps0
664			 (if standalone-executable
665			     cleanup-forms
666			     '((##core#undefined))))))
667
668	     (unless (null? import-libraries)
669	       (quit-compiling
670		"No module definition found for import libraries to emit: ~A"
671		;; ~S would be confusing: separate with a comma
672		(string-intersperse
673		 (map (lambda (il) (->string (car il)))
674		      import-libraries) ", ")))
675
676	     (when (pair? compiler-syntax-statistics)
677	       (with-debugging-output
678		'S
679		(lambda ()
680		  (print "applied compiler syntax:")
681		  (for-each
682		   (lambda (cs) (printf "  ~a\t\t~a~%" (car cs) (cdr cs)))
683		   compiler-syntax-statistics))))
684   	     (when (debugging '|N| "real name table:")
685	       (display-real-name-table) )
686	     (when (debugging 'n "line number database:")
687	       (##sys#display-line-number-database) )
688
689	     (set! ##sys#line-number-database line-number-database-2)
690	     (set! line-number-database-2 #f)
691
692	     (end-time "canonicalization")
693	     (print-expr "canonicalized" '|2| exps)
694
695	     (when (memq 'check-syntax options) (exit))
696
697	     ;; User-defined pass (s-expressions)
698	     (let ([proc (user-pass)])
699	       (when proc
700		 (dribble "User pass...")
701		 (begin-time)
702		 (set! exps (map proc exps))
703		 (end-time "user pass") ) )
704
705	     ;; Convert s-expressions to node tree
706	     (let ((node0 (build-toplevel-procedure
707			   (build-node-graph
708			    (canonicalize-begin-body exps))))
709		   (db #f))
710	       (print-node "initial node tree" '|T| node0)
711	       (initialize-analysis-database)
712
713	       ;; collect requirements and load inline files
714	       (let ((extensions required-extensions))
715		 (when enable-inline-files
716		   (for-each
717		    (lambda (id)
718		      (and-let* ((ifile (##sys#resolve-include-filename
719					 (symbol->string id) '(".inline") #t #f)))
720			(dribble "Loading inline file ~a ..." ifile)
721			(load-inline-file ifile)))
722		    extensions))
723		 (let ((ifs (collect-options 'consult-inline-file)))
724		   (unless (null? ifs)
725		     (set! inline-locally #t)
726		     (for-each
727		      (lambda (ilf)
728			(dribble "Loading inline file ~a ..." ilf)
729			(load-inline-file ilf) )
730		      ifs)))
731		 ;; Perform scrutiny and optionally specialization
732		 (when (or do-scrutinize enable-specialization)
733		   ;;XXX hardcoded database file name
734		   (unless (memq 'ignore-repository options)
735		     (unless (load-type-database "types.db"
736						 enable-specialization)
737		       (quit-compiling
738			"default type-database `types.db' not found")))
739		   (for-each
740		    (lambda (fn)
741		      (or (load-type-database fn enable-specialization #f)
742			  (quit-compiling "type-database `~a' not found" fn)))
743		    (collect-options 'consult-types-file))
744		   (for-each
745		    (lambda (id)
746		      (load-type-database
747		       (make-pathname #f (symbol->string id) "types")
748		       enable-specialization))
749		    extensions)
750		   (begin-time)
751		   (set! first-analysis #f)
752		   (set! db (analyze 'scrutiny node0))
753		   (print-db "analysis" '|0| db 0)
754		   (end-time "pre-analysis (scrutiny)")
755		   (begin-time)
756		   (debugging 'p "performing scrutiny")
757		   (scrutinize node0 db
758			       do-scrutinize enable-specialization
759			       strict-variable-types block-compilation)
760		   (end-time "scrutiny")
761		   (when enable-specialization
762		     (print-node "specialization" '|P| node0))
763		   (set! first-analysis #t) ) )
764
765	       ;; TODO: Move this so that we don't need to export these
766	       (set! ##sys#line-number-database #f)
767	       (set! constant-table #f)
768	       (set! inline-table #f)
769	       ;; Analyze toplevel assignments
770	       (unless unsafe
771		 (scan-toplevel-assignments (first (node-subexpressions node0))) )
772
773	       (begin-time)
774	       ;; Convert to CPS
775	       (let ([node1 (perform-cps-conversion node0)])
776		 (end-time "cps conversion")
777		 (print-node "cps" '|3| node1)
778
779		 ;; Optimization loop:
780		 (let loop ((i 1)
781			    (node2 node1)
782                            (progress #t))
783		   (begin-time)
784		   ;; Analyze node tree for optimization
785		   (let ([db (analyze 'opt node2 i progress)])
786		     (when first-analysis
787		       (when (memq 'u debugging-chicken)
788			 (dump-undefined-globals db))
789		       (when (memq 'd debugging-chicken)
790			 (dump-defined-globals db))
791		       (when (memq 'v debugging-chicken)
792			 (dump-global-refs db))
793		       ;; do this here, because we must make sure we have a db
794		       (and-let* ((tfile (or (and (eq? types-output-file #t)
795						  (pathname-replace-extension filename "types"))
796					     (and (string? types-output-file)
797						  types-output-file))))
798			 (dribble "generating type file `~a' ..." tfile)
799			 (emit-types-file filename tfile db block-compilation)))
800		     (set! first-analysis #f)
801		     (end-time "analysis")
802		     (print-db "analysis" '|4| db i)
803
804		     (when (memq 's debugging-chicken)
805		       (print-program-statistics db))
806
807		     ;; Optimize (once)
808		     (cond (progress
809			    (debugging 'p "optimization pass" i)
810			    (begin-time)
811			    (receive (node2 progress-flag)
812				    (perform-high-level-optimizations
813				     node2 db block-compilation
814				     inline-locally inline-max-size
815                                     unroll-limit
816                                   inline-substitutions-enabled)
817			      (end-time "optimization")
818			      (print-node "optimized-iteration" '|5| node2)
819			      (cond (progress-flag
820                                     (loop (add1 i) node2 #t))
821				    ((not inline-substitutions-enabled)
822				     (debugging 'p "rewritings enabled")
823				     (set! inline-substitutions-enabled #t)
824                                     (loop (add1 i) node2 #t) )
825				    (optimize-leaf-routines
826				     (begin-time)
827				     (let ([db (analyze 'leaf node2)])
828				       (end-time "analysis")
829				       (begin-time)
830				       (let ((progress
831					      (transform-direct-lambdas! node2 db)))
832					 (end-time "leaf routine optimization")
833					 (loop (add1 i)
834					       node2
835                                               progress) ) ) )
836				    (else
837                                     (loop (add1 i) node2 #f)) ) ) )
838
839			   (else
840			    ;; Secondary flow-analysis
841			    (when do-lfa2
842			      (begin-time)
843			      (debugging 'p "doing lfa2")
844                              (let ((floatvars (perform-secondary-flow-analysis node2 db)))
845  			        (end-time "secondary flow analysis")
846                                (unless (null? floatvars)
847                                  (begin-time)
848                                  (debugging 'p "doing unboxing")
849                                  (set! node2 (perform-unboxing node2 floatvars)))
850    			          (end-time "unboxing")))
851			    (print-node "optimized" '|7| node2)
852			    ;; inlining into a file with interrupts enabled would
853			    ;; change semantics
854			    (when (and inline-output-file insert-timer-checks)
855			      (let ((f inline-output-file))
856				(dribble "generating global inline file `~a' ..." f)
857				(emit-global-inline-file
858				 filename f db block-compilation
859				 inline-max-size
860				 (map foreign-stub-id foreign-lambda-stubs)) ) )
861			    (begin-time)
862			    ;; Closure conversion
863			    (set! node2 (perform-closure-conversion node2 db))
864			    (end-time "closure conversion")
865			    (print-db "final-analysis" '|8| db i)
866			    (when (and ##sys#warnings-enabled
867				       (> (- (cputime) start-time) funny-message-timeout))
868			      (display "(don't worry - still compiling...)\n") )
869			    (print-node "closure-converted" '|9| node2)
870			    (when a-only (exit 0))
871			    (begin-time)
872			    ;; Preparation
873			    (receive (node literals lliterals lambda-table dbg-info)
874				(prepare-for-code-generation node2 db)
875			      (end-time "preparation")
876			      (begin-time)
877
878                              ;; generate link file
879			      (when emit-link-file
880				(let ((exts required-extensions))
881				  (dribble "generating link file `~a' ..." emit-link-file)
882				  (with-output-to-file emit-link-file (cut pp exts))))
883
884                               ;; Code generation
885			      (let ((out (if tmp-outfile
886                                             (open-output-file tmp-outfile)
887                                             (current-output-port))) )
888                                (when tmp-outfile
889                                  (dribble "generating `~A' ..." tmp-outfile))
890				(generate-code literals lliterals lambda-table out filename
891					       user-supplied-options dynamic db dbg-info)
892				(when tmp-outfile
893                                  (close-output-port out)
894                                  (rename-file tmp-outfile outfile #t)))
895			      (end-time "code generation")
896			      (when (memq 't debugging-chicken)
897				(##sys#display-times (##sys#stop-timer)))
898			      (compiler-cleanup-hook)
899			      (dribble "compilation finished.") ) ) ) ) ) ) ) ) ) ) ) )
900)
Trap