~ chicken-core (master) /batch-driver.scm
Trap1;;;; batch-driver.scm - Driver procedure for the compiler2;3; Copyright (c) 2008-2022, The CHICKEN Team4; Copyright (c) 2000-2007, Felix L. Winkelmann5; All rights reserved.6;7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following8; conditions are met:9;10; Redistributions of source code must retain the above copyright notice, this list of conditions and the following11; disclaimer.12; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following13; 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 promote15; 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 EXPRESS18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE25; POSSIBILITY OF SUCH DAMAGE.262728(declare29 (unit batch-driver)30 (uses extras data-structures pathname expand31 support compiler-syntax compiler optimizer internal32 ;; TODO: Backend should be configurable33 scrutinizer lfa2 c-platform c-backend user-pass))3435(module chicken.compiler.batch-driver36 (compile-source-file)3738(import scheme39 chicken.base40 chicken.file41 chicken.fixnum42 chicken.format43 chicken.gc44 chicken.internal45 chicken.load46 chicken.pathname47 chicken.platform48 chicken.pretty-print49 chicken.process-context50 chicken.process-context.posix51 chicken.string52 chicken.syntax53 chicken.port54 chicken.time55 chicken.condition56 chicken.compiler.support57 chicken.compiler.compiler-syntax58 chicken.compiler.core59 chicken.compiler.optimizer60 chicken.compiler.scrutinizer61 chicken.compiler.lfa262 chicken.compiler.c-platform63 chicken.compiler.c-backend64 chicken.compiler.user-pass)6566(include "tweaks")67(include "mini-srfi-1.scm")6869(define-constant funny-message-timeout 60000)7071;;; Emit collected information from various statistics about the program7273(define (print-program-statistics db)74 (receive75 (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) ) ) )8384;;; 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 to88;; have the option to add default entries for each new db.8990(define initialize-analysis-database91 (let ((initial #t))92 (lambda ()93 (when initial94 (for-each95 (lambda (s)96 (mark-variable s '##compiler#intrinsic 'standard))97 standard-bindings)98 (for-each99 (lambda (s)100 (mark-variable s '##compiler#intrinsic 'extended))101 extended-bindings)102 (for-each103 (lambda (s)104 (mark-variable s '##compiler#intrinsic 'internal))105 internal-bindings))106 (set! initial #f))))107108;;; Display analysis database:109110(define display-analysis-database111 (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 omit125 (set! omit126 (append default-standard-bindings127 default-extended-bindings128 internal-bindings) ) )129 (hash-table-for-each130 (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 (begin142 (case (caar es)143 ((captured assigned boxed global contractable standard-binding assigned-locally144 collapsable removable undefined replacing unused simple inlinable inline-export145 has-unused-parameters extended-binding customizable constant boxed-rest hidden-refs146 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-parameter157 captured-variables explicit-rest rest-cdr rest-null? consed-rest-arg158 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-each177 (lambda (pval)178 (printf "\tpval=~s" (cons (node-class pval) (node-parameters pval))))179 pvals))180 (newline) ) ) )181 db) ) ) )182183;;; Compile a complete source file:184185(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#declare206 ,@(append207 default-declarations208 (if emit-debug-info209 '((uses debugger-client))210 '())211 (if explicit-use-flag212 '()213 `((uses ,@default-units)))214 (if (and static-extensions215 (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-flag224 '()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 it236 ;; can atomically be renamed to the actual output file after237 ;; the C generation.238 (tmp-outfile (and outfile239 (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-name249 (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-name260 (and-let* ((m (memq 'module options)))261 (option-arg m))))262263 (define (cputime) (current-process-milliseconds))264265 (define (dribble fstr . args)266 (debugging 'p (apply sprintf fstr args)))267268 (define (print-header mode dbgmode)269 (debugging 'p "pass" mode)270 (and (memq dbgmode debugging-chicken)271 (begin272 (printf "[~a]~%" mode)273 #t) ) )274275 (define (print-node mode dbgmode n)276 (when (print-header mode dbgmode)277 (if dumpnodes278 (dump-nodes n)279 (pretty-print (build-expression-tree n)) ) ) )280281 (define (print-db mode dbgmode db pass)282 (when (print-header mode dbgmode)283 (printf "(iteration ~s)~%" pass)284 (display-analysis-database db) ) )285286 (define (print-expr mode dbgmode xs)287 (when (print-header mode dbgmode)288 (for-each289 (lambda (x)290 (pretty-print x)291 (newline))292 xs) ) )293294 (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)))))303304 (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 ex309 (##sys#error "invalid import specification" str)310 (with-input-from-string str read))311 (string->symbol str))))312313 (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) ) ) )323324 (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 '()] ) ) )328329 (define (begin-time)330 (when time-breakdown (set! time0 (cputime))) )331332 (define (end-time pass)333 (when time-breakdown334 (printf "milliseconds needed for ~a: \t~s~%"335 pass336 (inexact->exact (round (- (cputime) time0)) ) )))337338 (define (analyze pass node . args)339 (let-optionals args ((no 0) (contf #t))340 (let ((db (analyze-expression node)))341 (when upap342 (upap pass db node343 (cut db-get db <> <>)344 (cut db-put! db <> <> <>)345 no contf) )346 db) ) )347348 (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) ) )354355 (when unit356 (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-chicken364 (append-map365 (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-libraries374 (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-specialization382 (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 time409 (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 sense426 (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-size432 (let ([arg (option-arg inlimit)])433 (or (string->number arg)434 (quit-compiling435 "invalid argument to `-inline-limit' option: `~A'" arg) ) ) ) )436 (and-let* ((ulimit (memq 'unroll-limit options)))437 (set! unroll-limit438 (let ((arg (option-arg ulimit)))439 (or (string->number arg)440 (quit-compiling441 "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 kwstyle447 (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-compiling452 "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-pathnames463 (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-each479 (lambda (v)480 (mark-variable v '##compiler#always-bound-to-procedure)481 (mark-variable v '##compiler#always-bound) )482 default-standard-bindings)483 (for-each484 (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))489490 ;; Handle feature options:491 (for-each492 register-feature!493 (append-map (cut string-split <> ", ") (collect-options 'feature)))494 (for-each495 unregister-feature!496 (append-map (cut string-split <> ",") (collect-options 'no-feature)))497498 ;; Load extensions:499 (set! ##sys#features (cons #:compiler-extension ##sys#features))500 (let ([extends (collect-options 'extend)])501 (dribble "Loading compiler extensions...")502 (for-each503 (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))511512 ;; Handle units added with the "-uses" flag.513 (let ((uses (append-map514 (lambda (u) (map string->symbol (string-split u ", ")))515 (collect-options 'uses))))516 (unless (null? uses)517 (set! init-forms518 (append init-forms `((##core#declare (uses . ,uses)))))))519520 ;; Mark linked libraries so they will be compiled as unit dependencies.521 (let ((link (append-map522 (lambda (l) (map string->symbol (string-split l ", ")))523 (collect-options 'link))))524 (set! linked-libraries (lset-union/eq? linked-libraries link)))525526 ;; Append required extensions to imports:527 (set! import-forms528 (append529 import-forms530 (map (lambda (r) `(import ,(string->extension-name r)))531 (collect-options 'require-extension))))532533 (when (memq 'compile-syntax options)534 (set! ##sys#enable-runtime-macros #t) )535 (set! target-heap-size536 (and hsize537 (arg-val (option-arg hsize))))538 (set! target-stack-size539 (and ssize540 (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 (else548 (set! standard-bindings default-standard-bindings)549 (set! extended-bindings default-extended-bindings) ))550 (dribble "debugging info: ~A"551 (if emit-trace-info552 "calltrace"553 "none") )554 (when profile555 (let ((acc (eq? 'accumulate-profile (car profile))))556 (when (and acc (not profile-name))557 (quit-compiling558 "you need to specify -profile-name if using accumulated profiling runs"))559 (set! emit-profile #t)560 (set! profiled-procedures 'all)561 (set! init-forms562 (append563 init-forms564 default-profiling-declarations565 (if acc566 '((set! ##sys#profile-append-mode #t))567 '() ) ) )568 (dribble "generating ~aprofiled code" (if acc "accumulative " "")) ))569570 ;;XXX hardcoded "modules.db" is bad (also used in chicken-install.scm)571 (load-identifier-database "modules.db")572573 (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 (else587588 ;; 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))595596 ;; 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 (append601 (collect-options 'prologue)602 (list filename)603 (collect-options 'epilogue) ) ] )604605 (let ([proc (user-read-pass)])606 (cond [proc607 (dribble "User read pass...")608 (set! forms (proc prelude files postlude)) ]609 [else610 (do ([files files (cdr files)])611 ((null? files)612 (set! forms613 (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 namespacing621622 (cond ((eof-object? x)623 (close-checked-input-file in f) )624 (else625 (set! forms (cons x forms))626 (loop)))))))) ] ) ) )627628 ;; Start compilation passes:629 (let ([proc (user-preprocessor-pass)])630 (when proc631 (dribble "User preprocessing pass...")632 (set! forms (map proc forms))))633634 (print-expr "source" '|1| forms)635 (begin-time)636 ;; Canonicalize s-expressions637 (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 forms644 `((##core#module645 ,(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 (append651 (map (lambda (ic) `(set! ,(cdr ic) ',(car ic))) immutable-constants)652 init0653 uses0654 (if unit-name `((##core#provide ,unit-name)) '())655 (if emit-profile656 (profiling-prelude-exps (and (not unit-name)657 (or profile-name #t)))658 '() )659 exps0660 (if standalone-executable661 cleanup-forms662 '((##core#undefined))))))663664 (unless (null? import-libraries)665 (quit-compiling666 "No module definition found for import libraries to emit: ~A"667 ;; ~S would be confusing: separate with a comma668 (string-intersperse669 (map (lambda (il) (->string (car il)))670 import-libraries) ", ")))671672 (when (pair? compiler-syntax-statistics)673 (with-debugging-output674 'S675 (lambda ()676 (print "applied compiler syntax:")677 (for-each678 (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) )684685 (set! ##sys#line-number-database line-number-database-2)686 (set! line-number-database-2 #f)687688 (end-time "canonicalization")689 (print-expr "canonicalized" '|2| exps)690691 (when (memq 'check-syntax options) (exit))692693 ;; User-defined pass (s-expressions)694 (let ([proc (user-pass)])695 (when proc696 (dribble "User pass...")697 (begin-time)698 (set! exps (map proc exps))699 (end-time "user pass") ) )700701 ;; Convert s-expressions to node tree702 (let ((node0 (build-toplevel-procedure703 (build-node-graph704 (canonicalize-begin-body exps))))705 (db #f))706 (print-node "initial node tree" '|T| node0)707 (initialize-analysis-database)708709 ;; collect requirements and load inline files710 (let ((extensions required-extensions))711 (when enable-inline-files712 (for-each713 (lambda (id)714 (and-let* ((ifile (##sys#resolve-include-filename715 (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-each723 (lambda (ilf)724 (dribble "Loading inline file ~a ..." ilf)725 (load-inline-file ilf) )726 ifs)))727 ;; Perform scrutiny and optionally specialization728 (when (or do-scrutinize enable-specialization)729 ;;XXX hardcoded database file name730 (unless (memq 'ignore-repository options)731 (unless (load-type-database "types.db"732 enable-specialization)733 (quit-compiling734 "default type-database `types.db' not found")))735 (for-each736 (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-each741 (lambda (id)742 (load-type-database743 (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 db754 do-scrutinize enable-specialization755 strict-variable-types block-compilation)756 (end-time "scrutiny")757 (when enable-specialization758 (print-node "specialization" '|P| node0))759 (set! first-analysis #t) ) )760761 ;; TODO: Move this so that we don't need to export these762 (set! ##sys#line-number-database #f)763 (set! constant-table #f)764 (set! inline-table #f)765 ;; Analyze toplevel assignments766 (unless unsafe767 (scan-toplevel-assignments (first (node-subexpressions node0))) )768769 (begin-time)770 ;; Convert to CPS771 (let ([node1 (perform-cps-conversion node0)])772 (end-time "cps conversion")773 (print-node "cps" '|3| node1)774775 ;; Optimization loop:776 (let loop ((i 1)777 (node2 node1)778 (progress #t))779 (begin-time)780 ;; Analyze node tree for optimization781 (let ([db (analyze 'opt node2 i progress)])782 (when first-analysis783 (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 db790 (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)799800 (when (memq 's debugging-chicken)801 (print-program-statistics db))802803 ;; Optimize (once)804 (cond (progress805 (debugging 'p "optimization pass" i)806 (begin-time)807 (receive (node2 progress-flag)808 (perform-high-level-optimizations809 node2 db block-compilation810 inline-locally inline-max-size811 unroll-limit812 inline-substitutions-enabled)813 (end-time "optimization")814 (print-node "optimized-iteration" '|5| node2)815 (cond (progress-flag816 (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-routines822 (begin-time)823 (let ([db (analyze 'leaf node2)])824 (end-time "analysis")825 (begin-time)826 (let ((progress827 (transform-direct-lambdas! node2 db)))828 (end-time "leaf routine optimization")829 (loop (add1 i)830 node2831 progress) ) ) )832 (else833 (loop (add1 i) node2 #f)) ) ) )834835 (else836 ;; Secondary flow-analysis837 (when do-lfa2838 (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 would849 ;; change semantics850 (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-file854 filename f db block-compilation855 inline-max-size856 (map foreign-stub-id foreign-lambda-stubs)) ) )857 (begin-time)858 ;; Closure conversion859 (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-enabled863 (> (- (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 ;; Preparation869 (receive (node literals lliterals lambda-table dbg-info)870 (prepare-for-code-generation node2 db)871 (end-time "preparation")872 (begin-time)873874 ;; generate link file875 (when emit-link-file876 (let ((exts required-extensions))877 (dribble "generating link file `~a' ..." emit-link-file)878 (with-output-to-file emit-link-file (cut pp exts))))879880 ;; Code generation881 (let ((out (if tmp-outfile882 (open-output-file tmp-outfile)883 (current-output-port))) )884 (when tmp-outfile885 (dribble "generating `~A' ..." tmp-outfile))886 (generate-code literals lliterals lambda-table out filename887 user-supplied-options dynamic db dbg-info)888 (when tmp-outfile889 (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)