~ 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 '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 time413 (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 sense430 (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-size436 (let ([arg (option-arg inlimit)])437 (or (string->number arg)438 (quit-compiling439 "invalid argument to `-inline-limit' option: `~A'" arg) ) ) ) )440 (and-let* ((ulimit (memq 'unroll-limit options)))441 (set! unroll-limit442 (let ((arg (option-arg ulimit)))443 (or (string->number arg)444 (quit-compiling445 "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 kwstyle451 (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-compiling456 "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-pathnames467 (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-each483 (lambda (v)484 (mark-variable v '##compiler#always-bound-to-procedure)485 (mark-variable v '##compiler#always-bound) )486 default-standard-bindings)487 (for-each488 (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))493494 ;; Handle feature options:495 (for-each496 register-feature!497 (append-map (cut string-split <> ", ") (collect-options 'feature)))498 (for-each499 unregister-feature!500 (append-map (cut string-split <> ",") (collect-options 'no-feature)))501502 ;; Load extensions:503 (set! ##sys#features (cons #:compiler-extension ##sys#features))504 (let ([extends (collect-options 'extend)])505 (dribble "Loading compiler extensions...")506 (for-each507 (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))515516 ;; Handle units added with the "-uses" flag.517 (let ((uses (append-map518 (lambda (u) (map string->symbol (string-split u ", ")))519 (collect-options 'uses))))520 (unless (null? uses)521 (set! init-forms522 (append init-forms `((##core#declare (uses . ,uses)))))))523524 ;; Mark linked libraries so they will be compiled as unit dependencies.525 (let ((link (append-map526 (lambda (l) (map string->symbol (string-split l ", ")))527 (collect-options 'link))))528 (set! linked-libraries (lset-union/eq? linked-libraries link)))529530 ;; Append required extensions to imports:531 (set! import-forms532 (append533 import-forms534 (map (lambda (r) `(import ,(string->extension-name r)))535 (collect-options 'require-extension))))536537 (when (memq 'compile-syntax options)538 (set! ##sys#enable-runtime-macros #t) )539 (set! target-heap-size540 (and hsize541 (arg-val (option-arg hsize))))542 (set! target-stack-size543 (and ssize544 (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 (else552 (set! standard-bindings default-standard-bindings)553 (set! extended-bindings default-extended-bindings) ))554 (dribble "debugging info: ~A"555 (if emit-trace-info556 "calltrace"557 "none") )558 (when profile559 (let ((acc (eq? 'accumulate-profile (car profile))))560 (when (and acc (not profile-name))561 (quit-compiling562 "you need to specify -profile-name if using accumulated profiling runs"))563 (set! emit-profile #t)564 (set! profiled-procedures 'all)565 (set! init-forms566 (append567 init-forms568 default-profiling-declarations569 (if acc570 '((set! ##sys#profile-append-mode #t))571 '() ) ) )572 (dribble "generating ~aprofiled code" (if acc "accumulative " "")) ))573574 ;;XXX hardcoded "modules.db" is bad (also used in chicken-install.scm)575 (load-identifier-database "modules.db")576577 (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 (else591592 ;; 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))599600 ;; 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 (append605 (collect-options 'prologue)606 (list filename)607 (collect-options 'epilogue) ) ] )608609 (let ([proc (user-read-pass)])610 (cond [proc611 (dribble "User read pass...")612 (set! forms (proc prelude files postlude)) ]613 [else614 (do ([files files (cdr files)])615 ((null? files)616 (set! forms617 (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 namespacing625626 (cond ((eof-object? x)627 (close-checked-input-file in f) )628 (else629 (set! forms (cons x forms))630 (loop)))))))) ] ) ) )631632 ;; Start compilation passes:633 (let ([proc (user-preprocessor-pass)])634 (when proc635 (dribble "User preprocessing pass...")636 (set! forms (map proc forms))))637638 (print-expr "source" '|1| forms)639 (begin-time)640 ;; Canonicalize s-expressions641 (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 forms648 `((##core#module649 ,(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 (append655 (map (lambda (ic) `(set! ,(cdr ic) ',(car ic))) immutable-constants)656 init0657 uses0658 (if unit-name `((##core#provide ,unit-name)) '())659 (if emit-profile660 (profiling-prelude-exps (and (not unit-name)661 (or profile-name #t)))662 '() )663 exps0664 (if standalone-executable665 cleanup-forms666 '((##core#undefined))))))667668 (unless (null? import-libraries)669 (quit-compiling670 "No module definition found for import libraries to emit: ~A"671 ;; ~S would be confusing: separate with a comma672 (string-intersperse673 (map (lambda (il) (->string (car il)))674 import-libraries) ", ")))675676 (when (pair? compiler-syntax-statistics)677 (with-debugging-output678 'S679 (lambda ()680 (print "applied compiler syntax:")681 (for-each682 (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) )688689 (set! ##sys#line-number-database line-number-database-2)690 (set! line-number-database-2 #f)691692 (end-time "canonicalization")693 (print-expr "canonicalized" '|2| exps)694695 (when (memq 'check-syntax options) (exit))696697 ;; User-defined pass (s-expressions)698 (let ([proc (user-pass)])699 (when proc700 (dribble "User pass...")701 (begin-time)702 (set! exps (map proc exps))703 (end-time "user pass") ) )704705 ;; Convert s-expressions to node tree706 (let ((node0 (build-toplevel-procedure707 (build-node-graph708 (canonicalize-begin-body exps))))709 (db #f))710 (print-node "initial node tree" '|T| node0)711 (initialize-analysis-database)712713 ;; collect requirements and load inline files714 (let ((extensions required-extensions))715 (when enable-inline-files716 (for-each717 (lambda (id)718 (and-let* ((ifile (##sys#resolve-include-filename719 (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-each727 (lambda (ilf)728 (dribble "Loading inline file ~a ..." ilf)729 (load-inline-file ilf) )730 ifs)))731 ;; Perform scrutiny and optionally specialization732 (when (or do-scrutinize enable-specialization)733 ;;XXX hardcoded database file name734 (unless (memq 'ignore-repository options)735 (unless (load-type-database "types.db"736 enable-specialization)737 (quit-compiling738 "default type-database `types.db' not found")))739 (for-each740 (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-each745 (lambda (id)746 (load-type-database747 (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 db758 do-scrutinize enable-specialization759 strict-variable-types block-compilation)760 (end-time "scrutiny")761 (when enable-specialization762 (print-node "specialization" '|P| node0))763 (set! first-analysis #t) ) )764765 ;; TODO: Move this so that we don't need to export these766 (set! ##sys#line-number-database #f)767 (set! constant-table #f)768 (set! inline-table #f)769 ;; Analyze toplevel assignments770 (unless unsafe771 (scan-toplevel-assignments (first (node-subexpressions node0))) )772773 (begin-time)774 ;; Convert to CPS775 (let ([node1 (perform-cps-conversion node0)])776 (end-time "cps conversion")777 (print-node "cps" '|3| node1)778779 ;; Optimization loop:780 (let loop ((i 1)781 (node2 node1)782 (progress #t))783 (begin-time)784 ;; Analyze node tree for optimization785 (let ([db (analyze 'opt node2 i progress)])786 (when first-analysis787 (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 db794 (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)803804 (when (memq 's debugging-chicken)805 (print-program-statistics db))806807 ;; Optimize (once)808 (cond (progress809 (debugging 'p "optimization pass" i)810 (begin-time)811 (receive (node2 progress-flag)812 (perform-high-level-optimizations813 node2 db block-compilation814 inline-locally inline-max-size815 unroll-limit816 inline-substitutions-enabled)817 (end-time "optimization")818 (print-node "optimized-iteration" '|5| node2)819 (cond (progress-flag820 (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-routines826 (begin-time)827 (let ([db (analyze 'leaf node2)])828 (end-time "analysis")829 (begin-time)830 (let ((progress831 (transform-direct-lambdas! node2 db)))832 (end-time "leaf routine optimization")833 (loop (add1 i)834 node2835 progress) ) ) )836 (else837 (loop (add1 i) node2 #f)) ) ) )838839 (else840 ;; Secondary flow-analysis841 (when do-lfa2842 (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 would853 ;; change semantics854 (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-file858 filename f db block-compilation859 inline-max-size860 (map foreign-stub-id foreign-lambda-stubs)) ) )861 (begin-time)862 ;; Closure conversion863 (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-enabled867 (> (- (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 ;; Preparation873 (receive (node literals lliterals lambda-table dbg-info)874 (prepare-for-code-generation node2 db)875 (end-time "preparation")876 (begin-time)877878 ;; generate link file879 (when emit-link-file880 (let ((exts required-extensions))881 (dribble "generating link file `~a' ..." emit-link-file)882 (with-output-to-file emit-link-file (cut pp exts))))883884 ;; Code generation885 (let ((out (if tmp-outfile886 (open-output-file tmp-outfile)887 (current-output-port))) )888 (when tmp-outfile889 (dribble "generating `~A' ..." tmp-outfile))890 (generate-code literals lliterals lambda-table out filename891 user-supplied-options dynamic db dbg-info)892 (when tmp-outfile893 (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)