aboutsummaryrefslogtreecommitdiffstats
path: root/hobbit.texi
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2017-02-20 00:05:26 -0800
committerBryan Newbold <bnewbold@robocracy.org>2017-02-20 00:05:26 -0800
commitdeda2c0fd8689349fea2a900199a76ff7ecb319e (patch)
treec9726d54a0806a9b0c75e6c82db8692aea0053cf /hobbit.texi
parent3278b75942bdbe706f7a0fba87729bb1e935b68b (diff)
downloadscm-deda2c0fd8689349fea2a900199a76ff7ecb319e.tar.gz
scm-deda2c0fd8689349fea2a900199a76ff7ecb319e.zip
Import Upstream version 5d6upstream/5d6
Diffstat (limited to 'hobbit.texi')
-rw-r--r--hobbit.texi2273
1 files changed, 2273 insertions, 0 deletions
diff --git a/hobbit.texi b/hobbit.texi
new file mode 100644
index 0000000..3b448fb
--- /dev/null
+++ b/hobbit.texi
@@ -0,0 +1,2273 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename hobbit.info
+@settitle hobbit
+@include version.txi
+@setchapternewpage on
+@c Choices for setchapternewpage are {on,off,odd}.
+@paragraphindent 0
+@defcodeindex ft
+@syncodeindex ft cp
+@c %**end of header
+
+@dircategory The Algorithmic Language Scheme
+@direntry
+* hobbit: (hobbit). SCM Compiler.
+@end direntry
+
+@iftex
+@finalout
+@c DL: lose the egregious vertical whitespace, esp. around examples
+@c but paras in @defun-like things don't have parindent
+@parskip 4pt plus 1pt
+@end iftex
+
+@titlepage
+@title Hobbit
+@subtitle SCM Compiler
+@subtitle Version @value{SCMVERSION}
+@author by Tanel Tammet
+@author Department of Computing Science
+@author Chalmers University of Technology
+@author University of Go"teborg
+@author S-41296 Go"teborg Sweden
+
+@page
+This Hobbit documentation was converted to texinfo format by Aubrey
+Jaffer; and released as part of the SCM @value{SCMVERSION} distribution
+@value{SCMDATE}.
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990-1999, 2002 Free Software Foundation
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the author.
+@end titlepage
+
+@node Top, Introduction, (dir), (dir)
+
+@ifinfo
+Hobbit is an optimizing R4RS-Scheme to C compiler written by Tanel
+Tammet.
+
+@menu
+* Introduction::
+* Compiling with Hobbit::
+* The Language Compiled::
+* Performance of Compiled Code::
+* Principles of Compilation::
+* About Hobbit::
+@end menu
+
+Copyright (C) 1990-1999, 2002 Free Software Foundation
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the author.
+@end ifinfo
+
+
+@node Introduction, Compiling with Hobbit, Top, Top
+@chapter Introduction
+
+Hobbit is a small optimizing scheme-to-C compiler written in Report 4
+scheme and intended for use together with the SCM scheme interpreter of
+A. Jaffer. Hobbit compiles full Report 4 scheme, except that:
+
+@itemize @bullet
+@item
+It does not fully conform to the requirement of being properly
+tail-recursive: non-mutual tailrecursion is detected, but mutual
+tailrecursion is not.
+@item
+Macros from the Report 4 appendix are not supported (yet):
+only the common-lisp-like defmacro is supported.
+@end itemize
+
+Hobbit treats SCM files as a C library and provides integration of
+compiled procedures and variables with the SCM interpreter as new
+primitives.
+
+Hobbit compiles scheme files to C files and does not provide anything
+else by itself (eg. calling the C compiler, dynamic loading). Such
+niceties are described in the next chapter @ref{Compiling And Linking}.
+
+Hobbit (derived from hobbit5x) is now part of the SCM Scheme
+implementation. The most recent information about SCM can be found on
+SCM's @dfn{WWW} home page:
+
+@center @url{http://swissnet.ai.mit.edu/~jaffer/SCM.html}
+
+Hobbit4d has also been ported to the Guile Scheme implementation:
+
+@center @url{http://www.gnu.org/software/guile/anon-cvs.html}
+
+
+@node Compiling with Hobbit, The Language Compiled, Introduction, Top
+@chapter Compiling with Hobbit
+
+@menu
+* Compiling And Linking::
+* Error Detection::
+* Hobbit Options::
+* CC Optimizations::
+@end menu
+
+@node Compiling And Linking, Error Detection, Compiling with Hobbit, Compiling with Hobbit
+@section Compiling And Linking
+
+@code{(require 'compile)}
+
+@defun hobbit name1.scm name2.scm @dots{}
+Invokes the HOBBIT compiler to translate Scheme files
+@file{@var{name1}.scm}, @file{@var{name2}.scm}, @dots{} to C files
+@file{@var{name1}.c} and @file{@var{name1}.h}.
+@end defun
+
+@defun compile-file name1.scm name2.scm @dots{}
+Compiles the HOBBIT translation of @var{name1}.scm, @var{name2}.scm,
+@dots{} to a dynamically linkable object file
+@var{name1}<object-suffix>, where <object-suffix> is the object file
+suffix for your computer (for instance, @file{.so}). @var{name1}.scm
+must be in the current directory; @var{name2}.scm, @dots{} may be in
+other directories.
+@end defun
+
+@example
+cd ~/scm/
+scm -rcompile -e'(compile-file "example.scm")'
+
+Starting to read example.scm
+
+Generic (slow) arithmetic assumed: 1.0e-3 found.
+
+** Pass 1 completed **
+** Pass 2 completed **
+** Pass 3 completed **
+** Pass 4 completed **
+** Pass 5 completed **
+** Pass 6 completed **
+
+C source file example.c is built.
+C header file example.h is built.
+
+These top level higher order procedures are not clonable (slow):
+(nonkeyword_make-promise map-streams generate-vector runge-kutta-4)
+These top level procedures create non-liftable closures (slow):
+(nonkeyword_make-promise damped-oscillator map-streams scale-vector elementwise runge-kutta-4 integrate-system)
+
+; Scheme (linux) script created by SLIB/batch Sun Apr 7 22:49:49 2002
+; ================ Write file with C defines
+(delete-file "scmflags.h")
+(call-with-output-file
+ "scmflags.h"
+ (lambda (fp)
+ (for-each
+ (lambda (string) (write-line string fp))
+ '("#define IMPLINIT \"Init@value{SCMVERSION}.scm\""
+ "#define BIGNUMS"
+ "#define FLOATS"
+ "#define ARRAYS"
+ "#define DLL"))))
+; ================ Compile C source files
+(system "gcc -O2 -fpic -c -I/usr/local/lib/scm/ example.c")
+(system "gcc -shared -o example.so example.o -lm -lc")
+(delete-file "example.o")
+; ================ Link C object files
+(delete-file "slibcat")
+
+Compilation finished at Sun Apr 7 22:49:50
+@end example
+
+@defun compile->executable exename name1.scm name2.scm @dots{}
+Compiles and links the HOBBIT translation of @var{name1}.scm,
+@var{name2}.scm, @dots{} to a SCM executable named @var{exename}.
+@var{name1}.scm must be in the current directory; @var{name2}.scm,
+@dots{} may be in other directories.
+@end defun
+
+@example
+cd ~/scm/
+scm -rcompile -e'(compile->executable "exscm" "example.scm")'
+
+Starting to read example.scm
+
+Generic (slow) arithmetic assumed: 1.0e-3 found.
+
+** Pass 1 completed **
+** Pass 2 completed **
+** Pass 3 completed **
+** Pass 4 completed **
+** Pass 5 completed **
+** Pass 6 completed **
+
+C source file example.c is built.
+C header file example.h is built.
+
+These top level higher order procedures are not clonable (slow):
+(nonkeyword_make-promise map-streams generate-vector runge-kutta-4)
+These top level procedures create non-liftable closures (slow):
+(nonkeyword_make-promise damped-oscillator map-streams scale-vector elementwise runge-kutta-4 integrate-system)
+
+; Scheme (linux) script created by SLIB/batch Sun Apr 7 22:46:31 2002
+; ================ Write file with C defines
+(delete-file "scmflags.h")
+(call-with-output-file
+ "scmflags.h"
+ (lambda (fp)
+ (for-each
+ (lambda (string) (write-line string fp))
+ '("#define IMPLINIT \"Init@value{SCMVERSION}.scm\""
+ "#define COMPILED_INITS init_example();"
+ "#define CCLO"
+ "#define FLOATS"))))
+; ================ Compile C source files
+(system "gcc -O2 -c continue.c scmmain.c findexec.c script.c time.c repl.c scl.c eval.c sys.c subr.c debug.c unif.c rope.c example.c scm.c")
+; ================ Link C object files
+(system "gcc -rdynamic -o exscm continue.o scmmain.o findexec.o script.o time.o repl.o scl.o eval.o sys.o subr.o debug.o unif.o rope.o example.o scm.o -L/usr/local/lib/scm/ -lm -lc")
+
+Compilation finished at Sun Apr 7 22:46:44
+@end example
+
+@emph{Note Bene:} @samp{#define CCLO} must be present in @file{scmfig.h}.
+
+In order to see calls to the C compiler and linker, do
+
+@example
+(verbose 3)
+@end example
+
+before calling these functions.
+
+
+@node Error Detection, Hobbit Options, Compiling And Linking, Compiling with Hobbit
+@section Error Detection
+
+Error detection during compilation is minimal. In case your scheme code
+is syntactically incorrect, hobbit may crash with no sensible error
+messages or it may produce incorrect C code.
+
+Hobbit does not insert any type-checking code into the C output it
+produces. Eg, if a hobbit-compiled program applies @samp{car} to a
+number, the program will probably crash with no sensible error messages.
+
+Thus it is strongly suggested to compile only throughly debugged
+scheme code.
+
+Alternatively, it is possible to compile all the primitives into
+calls to the SCM procedures doing type-checking. Hobbit will do
+this if you tell it to assume that all the primitives may be
+redefined. Put
+
+@example
+(define compile-all-proc-redefined #t)
+@end example
+
+anywhere in top level of your scheme code to achieve this.
+
+@emph{Note Bene:} The compiled code using
+
+@example
+(define compile-all-proc-redefined #t)
+@end example
+
+will typically be much slower than one produced without using
+
+@example
+(define compile-all-proc-redefined #t).
+@end example
+
+All errors caught by hobbit will generate an error message
+
+@example
+@group
+COMPILATION ERROR:
+@r{<description of the error>}
+@end group
+@end example
+
+and hobbit will immediately halt compilation.
+
+
+@node Hobbit Options, CC Optimizations, Error Detection, Compiling with Hobbit
+@section Hobbit Options
+
+@enumerate
+@item
+Selecting the type of arithmetics.
+
+By default hobbit assumes that only immediate (ie small, up to 30 bits)
+integers are used. It will automatically assume general arithmetics in
+case it finds any non-immediate numbers like 1.2 or 10000000000000 or
+real-only procedures like @t{$sin} anywhere in the source.
+
+Another way to make Hobbit assume that generic arithmetic supported
+by SCM (ie exact and/or inexact reals, bignums) is also used, is to
+put the following line somewhere in your scheme source file:
+
+@example
+(define compile-allnumbers @var{t})
+@end example
+
+where @var{t} is arbitrary.
+
+In that case all the arithmetic primitives in all the given source
+files will be assumed to be generic. This will make operations
+with immediate integers much slower. You can use the special
+immediate-integer-only forms of arithmetic procedures to recover:
+
+@example
+@group
+%negative? %number? %> %>= %= %<= %<
+%positive? %zero? %eqv? %+ %- %* %/
+@end group
+@end example
+
+See @ref{The Language Compiled}.
+
+@item
+Redefinition of procedures.
+
+By default hobbit assumes that neither primitives nor compiled
+procedures are redefined, neither before the compiled program is
+initialized, during its work or later via the interpreter.
+
+Hobbit checks the compiled source and whenever some variable bar is
+defined as a procedure, but is later redefined, or @t{set!} is applied
+to bar, then hobbit assumes thas this particular variable bar is
+redefinable. bar may be a primitive (eg @samp{car}) or a name of a
+compiled procedure.
+
+
+@emph{Note Bene:}
+According to the Report 4 it is @b{NOT} allowed to use scheme
+keywords as variables (you may redefine these as macros defined by
+defmacro, though):
+
+@example
+@group
+=> and begin case cond define delay do else if lambda
+let let letrec or quasiquote quote set! unquote unquote-splicing
+@end group
+@end example
+
+If you want to be able to redefine some procedures, eg. @samp{+} and
+@samp{baz}, then put both
+
+@example
+@group
+(set! + +)
+(set! baz baz)
+@end group
+@end example
+
+somewhere into your file.
+
+As a consequence hobbit will generate code for @samp{+} and @samp{baz}
+using the run-time values of these variables. This is generally much
+slower than using non-redefined @samp{+} and @samp{baz} (especially for
+@samp{+}).
+
+If you want to be able to redefine all the procedures, both primitives
+(eg @samp{car}) and the compiled procedures, then put the following into
+the compiled file:
+
+@example
+(define compile-all-proc-redefined @var{t})
+@end example
+
+where @var{t} is arbitrary.
+
+If you want to be able to redefine all the compiled procedures, but not
+the scheme primitives, then put the following into the compiled file:
+
+@example
+(define compile-new-proc-redefined @var{t})
+@end example
+
+where @var{t} is arbitrary.
+
+Again, remember that redefinable procedures will be typically much
+slower than non-redefinable procedures.
+
+
+@item
+Inlined variables and procedures.
+
+You may inline top-level-defined variables and procedures.
+Notice that inlining is DIFFERENT for variables and procedures!
+
+NEVER inline variables or procedures which are @t{set!} or redefined
+anywhere in you program: this will produce wrong code.
+
+@itemize @bullet
+@item
+You may declare certain top-level defined variables to be inlined.
+For example, if the following variable foo is declared to be inlined
+@end itemize
+
+@example
+(define foo 100)
+@end example
+
+then @samp{foo} will be everywhere replaced by @samp{100}.
+
+To declare some variables foo and bar to be inlined, put a following
+definition anywhere into your file:
+
+@example
+(define compile-inline-vars '(foo bar))
+@end example
+
+Usually it makes sense to inline only these variables whose value
+is either a small integer, character or a boolean.
+
+
+@emph{Note Bene:}
+Do not use this kind of inlining for inlining procedures!
+Use the following for procedures:
+
+@itemize @bullet
+@item
+You may declare certain procedures to be inlined. For example, if
+the following foo is declared to be inlined
+@end itemize
+
+@example
+(define (foo x) (+ x 2))
+@end example
+
+then any call
+
+@example
+(foo @var{something})
+@end example
+
+will be replaced by
+
+@example
+(+ @var{something} 2)
+@end example
+
+Inlining is @b{NOT} safe for variable clashes -- in other words, it is
+not "hygienic".
+
+Inlining is @b{NOT} safe for recursive procedures -- if the set of
+inlined procedures contains either immediate or mutual (foo calling
+bar, bar calling foo) recursion, the compiler will not terminate.
+To turn off full inlining (harmful for recursive funs), change
+the definition of the *full-inlining-flag* in the section
+"compiler options" to the value #f instead of #t.
+
+To declare some procedures foo and bar to be inlined, put a following
+definition anywhere into your file:
+
+@example
+(define compile-inline '(foo bar))
+@end example
+
+@item
+Speeding up vectors:
+
+Put
+
+@example
+(define compile-stable-vectors '(baz foo))
+@end example
+
+into your file to declare that baz and foo are vector names defined once
+on the top level, and @t{set!} is never applied to them (@t{vector-set!}
+is, of course, allowed). This speeds up vector reference to those
+vectors by precomputing their location.
+
+@item
+Speeding up and hiding certain global variables:
+
+Put
+
+@example
+(define compile-uninterned-variables '(bazvar foovar))
+@end example
+
+into your file to declare that bazvar and foovar are defined on the top
+level and they do always have an immediate value, ie a boolean,
+immediate (30-bit) integer or a character. Then bazvar and foovar will
+@b{NOT} be accessible from the interpreter. They'll be compiled directly
+into static C vars and used without an extra C *-operation prefixed to
+other global scheme variables.
+
+@item
+Intermediate files
+
+To see the output of compiler passes, change the following
+definition in @file{hobbit.scm}.
+
+@example
+(define *build-intermediate-files* #f)
+@end example
+
+to:
+
+@example
+(define *build-intermediate-files* #t)
+@end example
+
+@item
+Name clashes
+
+It may happen that several originally different scheme variable
+names are represented by one and the same C variable. This will
+happen, for example, if you have separate variables a-1 and a_1.
+
+If such (or any other) name clashes occur you may
+need to change some control variables in the first sections
+of @file{hobbit.scm} (up to the section "global variable defs") or just
+rename some variables in your scheme program.
+
+@item
+Other options
+
+See various control variables in the first sections of @file{hobbit.scm}
+(up to section "global variable defs").
+@end enumerate
+
+
+
+@node CC Optimizations, , Hobbit Options, Compiling with Hobbit
+@section CC Optimizations
+
+When using the C compiler to compile the C code output by hobbit, always
+use strong optimizations (eg. @samp{cc -xO3} for cc on Sun, @samp{gcc
+-O2} or @samp{gcc -O3} for gcc). Hobbit does not attempt to do
+optimizations of the kind we anticipate from the C compiler, therefore
+it often makes a serious difference whether the C compiler is run with a
+strong optimization flag or not.
+
+For the final and fast version of your program you may want to first
+recompile the whole scm (scmlit for the version scm4e2) using the
+@samp{-DRECKLESS} flag suppressing error checking: the hobbit-compiled
+code uses some SCM primitives in the compiled files with the suffix .o,
+and a number of these primitives become faster when error checking is
+disabled by @samp{-DRECKLESS}. Notice that hobbit never inserts error
+checking into the code it produces.
+
+
+
+@node The Language Compiled, Performance of Compiled Code, Compiling with Hobbit, Top
+@chapter The Language Compiled
+
+Calls to @code{load} or @code{require} occurring at the top level of a
+file being compiled are ignored. Calls to @code{load} or @code{require}
+within a procedure are compiled to call (interpreted) @code{load} or
+@code{require} as appropriate.
+
+Several SCM and SLIB extensions to the Scheme report are recognized by
+hobbit as Scheme primitives.
+
+@menu
+* Macros::
+* SCM Primitive Procedures::
+* SLIB Logical Procedures::
+* Fast Integer Calculations::
+* Force and Delay::
+* Suggestions for writing fast code::
+@end menu
+
+
+@node Macros, SCM Primitive Procedures, The Language Compiled, The Language Compiled
+@section Macros
+@c @heading The SCM macro-facility and the SCM extra syntactic form
+
+The Common-lisp style defmacro implemented in SCM is recognized and
+procedures defined by defmacro are expanded during compilation.
+
+@emph{Note Bene:} any macro used in a compiled file must be also defined
+in one of the compiled files.
+
+@samp{#.@var{<expression>}} is read as the object resulting from the
+evaluation of @var{<expression>}. The calculation is performed during
+compile time. Thus @var{<expression>} must not contain variables
+defined or @t{set!} in the compiled file.
+
+
+@node SCM Primitive Procedures, SLIB Logical Procedures, Macros, The Language Compiled
+@section SCM Primitive Procedures
+@c @heading The SCM extra primitives
+
+Real-only versions of transcedental procedures (warning: these
+procedures are not compiled directly into the corresponding C library
+procedures, but a combination of internal SCM procedures, guaranteeing exact
+correspondence with the SCM interpreter while hindering the speed):
+
+@example
+@group
+$sqrt $abs $exp $log $sin $cos $tan $asin $acos
+$atan $sinh $cosh $tanh $asinh $acosh $atanh $expt
+@end group
+@end example
+
+@emph{Note Bene:} These procedures are compiled to faster code than the
+corresponding generic versions @t{sqrt}, @t{abs}, @dots{} @t{expt}.
+
+A selection of other extra primitives in SCM is also recognized as
+primitives. eg. @t{get-internal-run-time}, @t{quit}, @t{abort},
+@t{restart}, @t{chdir}, @t{delete-file}, @t{rename-file}.
+
+
+@node SLIB Logical Procedures, Fast Integer Calculations, SCM Primitive Procedures, The Language Compiled
+@section SLIB Logical Procedures
+@c @heading Bitwise logical procedures from the scheme library
+
+The following bitwise procedures in the scheme library file
+@file{logical.scm} are compiled directly to fast C operations on
+immediate integers (small 30-bit integers) (Scheme library funs in the
+upper row, C ops below):
+
+@example
+@group
+ logand logior logxor lognot logsleft logsright
+ & | ^ ~ << >>
+@end group
+@end example
+
+The following alternative names @t{logical:logand}, @t{logical:logior},
+@t{logical:logxor}, @t{logical:lognot}, @t{ash}, @t{logical:ash} are compiled for the
+generic case, not immediate-integers-only and are thus much slower.
+
+Notice that the procedures @t{logsleft}, @t{logsright} are @b{NOT} in
+the the library file @file{logical.scm:} the universal procedure @t{ash}
+is instead. Procedures @t{ash}, @t{logcount}, @t{integer-length},
+@t{integer-expt}, @t{bit-extract}, @t{ipow-by-squaring},
+@t{logical:ash}, @t{logical:logcount}, @t{logical:integer-length},
+@t{logical:integer-expt}, @t{logical:bit-extract},
+@t{logical:ipow-by-squaring}, in @file{logical.scm} are not primtives
+and they are all compiled into calls to interpreted code.
+
+@t{logsleft} and @t{logsright} are defined for non-compiled use in the
+file @file{scmhob.scm} included in the SCM distribution.
+
+
+@node Fast Integer Calculations, Force and Delay, SLIB Logical Procedures, The Language Compiled
+@section Fast Integer Calculations
+@c @heading Immediate (fast) arithmetics
+
+The following primitives are for immediate (30-bit) integer-only
+arithmetics. The are compiled directly into the corresponding C
+operations plus some bitshifts if necessary. They are good for speed in
+case the compiled program uses BOTH generic arithmetics (reals, bignums)
+and immediate (30-bit) integer arithmetics. These procedures are much
+faster than corresponding generic procedures taking also reals and
+bignums. There is no point in using these unless the program as a whole
+is compiled using generic arithmetics, since otherwise all the
+arithmetics procedures are compiled directly into corresponding C
+operations anyway.
+
+@emph{Note Bene:} These primitives are @b{NOT} defined in SCM or its
+libraries. For non-compiled use they are defined in the file
+@file{scmhob.scm} included in the SCM distribution.
+
+@example
+@group
+%negative? %number? %> %>= %= %<= %<
+%positive? %zero? %eqv? %+ %- %* %/
+@end group
+@end example
+
+@node Force and Delay, Suggestions for writing fast code, Fast Integer Calculations, The Language Compiled
+@section Force and Delay
+
+The nonessential procedure @code{force} and syntax @code{delay} are
+implemented exactly as suggested in the report 4. This implementation
+deviates internally from the implementation of @code{force} and
+@code{delay} in the SCM interpeter, thus it is incorrect to pass a
+promise created by @code{delay} in the compiled code to the @code{force}
+used by interpreter, and vice-versa for the promises created by the
+interpreter.
+
+
+
+@node Suggestions for writing fast code, , Force and Delay, The Language Compiled
+@section Suggestions for writing fast code
+
+The following suggestions may help you to write well-optimizable and
+fast code for the hobbit-scm combination. Roughly speaking, the main
+points are:
+
+@itemize
+@item
+minimizing consing and creation of new vectors and strings
+in speed-critical parts,
+
+@item
+minimizing the use of generic (non-integer) arithmetics
+in speed-critical parts,
+
+@item
+minimizing the usage of procedures as first-class
+objects (very roughly speaking, explicit lambda-terms
+and call/cc) in speed-critical parts,
+
+@item
+using special options and fast-compiled primitives of the compiler.
+@end itemize
+
+Here come the details.
+
+@enumerate
+@item
+Immediate arithmetics (ie using small, up to 30 bits integers) is much
+faster than generic (reals and bignums) arithmetics. If you have to use
+generic arithmetic in your program, then try to use special immediate
+arithmetics operations @code{%=}, @code{%<=}, @code{%+}, @code{%*},
+@dots{} for speed-critical parts of the program whenever possible.
+
+Also, if you use bitwise logical operations, try to use the
+immediate-integer-only versions
+
+@example
+logand logior logxor lognot logsleft logsright
+@end example
+
+and not @code{logical:logand} or @code{ash}, for example.
+
+@item
+Due to its inner stack-based architecture, the generic (not escape-only)
+continuations are very slow in SCM. Thus they are also slow in
+compiled code. Try to avoid continuations (calls to the procedure
+call-with-current-continuation and calls to the continuations it
+produces) in speed-critical parts.
+
+@item
+In speed-critical parts of your program try to avoid using procedures
+which are redefined or defined by @t{set!}:
+
+@example
+@group
+(set! bar +)
+(set! f (lambda (x) (if (zero? x) 1 (* x (f (- x 1))))))
+@end group
+@end example
+
+anywhere in the compiled program. Avoid using compiler flags
+(@pxref{Hobbit Options}):
+
+@example
+@group
+(define compile-all-proc-redefined @var{t})
+(define compile-new-proc-redefined @var{t})
+@end group
+@end example
+
+@item
+Do not use complicated higher-order procedures in speed-critical
+parts. By @dfn{complicated} we mean @dfn{not clonable}, where clonability
+is defined in the following way (@emph{Note Bene:} the primitives
+@samp{map} and @samp{for-each} are considered clonable and do not
+inflict a speed penalty).
+
+A higher-order procedure (HOP for short) is defined as a procedure
+with some of its formal arguments occuring in the procedure body in
+a function position, that is, as a first element of a list. Such
+an argument is called a @dfn{higher-order argument}.
+
+A HOP @samp{bar} is clonable iff it satisfies the following four
+conditions:
+
+@enumerate
+@item
+@samp{bar} is defined as
+
+@example
+(define bar (lambda @dots{}))
+@end example
+
+or
+
+@example
+(define (bar @dots{}) @dots{})
+@end example
+
+on top level and bar is not redefined anywhere.
+
+@item
+the name @samp{bar} occurs inside the body of bar only in a function position
+and not inside an internal lambda-term.
+
+@item
+Let f be a higher-order argument of bar.
+Any occurrence of f in bar has one of the following two forms:
+
+@itemize @bullet
+@item
+f occurs in a function position,
+@item
+f is passed as an argument to bar and in the call it occurs in the same
+position as in the argument list.
+@end itemize
+
+@item
+Let f be a higher-order argument of bar. f does not occur inside a
+lambda-term occurring in bar.
+
+Examples:
+
+If @samp{member-if} is defined on top level and is not redefined
+anywhere, then @samp{member-if} is a clonable HOP:
+
+@example
+@group
+(define (member-if fn lst)
+ (if (fn (car lst))
+ lst
+ (member-if fn (cdr lst)) ))
+@end group
+@end example
+
+member-if-not is not a clonable HOP (fn occurs in a lambdaterm):
+
+@example
+@group
+(define (member-if-not fn lst)
+ (member (lambda (x) (not (fn x))) lst) )
+@end group
+@end example
+
+show-f is not a clonable HOP (fn occurs in a non-function position
+in (display fn)):
+
+@example
+@group
+(define (show-f fn x)
+ (set! x (fn x))
+ (display fn)
+ x)
+@end group
+@end example
+
+@item
+In speed-critical parts avoid using procedures which return procedures.
+
+Eg, a procedure
+
+@example
+@group
+(define plus
+ (lambda (x)
+ (lambda (y) (+ y x)) ))
+@end group
+@end example
+
+returns a procedure.
+
+@item
+A generalisation of the previous case 5:
+
+In speed-critical parts avoid using lambda-terms except in non-@t{set!}
+function definitions like
+
+@example
+@group
+(define foo (lambda @dots{})),
+(let ((x 1) (f (lambda @dots{}))) @dots{})
+(let* ((x 1) (f (lambda @dots{}))) @dots{})
+(let name ((x 1) (f (lambda @dots{}))) @dots{})
+(letrec ((f (lambda @dots{})) (g (lambda @dots{}))) @dots{})
+@end group
+@end example
+
+or as arguments to clonable HOP-s or primitives @t{map} and
+@t{for-each}, like
+
+@example
+@group
+(let ((x 0)) (map (lambda (y) (set! x (+ 1 x)) (cons x y)) @var{list}))
+(member-if (lambda (x) (< x 0)) @var{list})
+@end group
+@end example
+
+where member-if is a clonable HOP.
+
+Also, avoid using variables with a procedural value anywhere
+except in a function position (first element of a list) or
+as an argument to a clonable HOP, @t{map} or @t{for-each}.
+
+Lambda-terms conforming to the current point are said to be liftable.
+
+Examples:
+
+@example
+(define (bar x) (let ((f car)) (f (f x))))
+@end example
+
+has @samp{car} in a non-function and non-HOP-argument position in
+@code{(f car)}, thus it is slower than
+
+@example
+(define (bar x) (let ((f 1)) (car (car x))))
+@end example
+
+Similarly,
+
+@example
+@group
+(define (bar y z w)
+ (let ((f (lambda (x) (+ x y))))
+ (set! w f)
+ (cons (f (car z))
+ (map f z) )))
+@end group
+@end example
+
+has @samp{f} occurring in a non-function position in @code{(set! w f)},
+thus the lambda-term @code{(lambda (x) (+ x y))} is not liftable and the
+upper @samp{bar} is thus slower than the following equivalent @samp{bar}
+with a liftable inner lambda-term:
+
+@example
+@group
+(define (bar y z w)
+ (let ((f (lambda (x) (+ x y))))
+ (set! w 0)
+ (cons (f (car z))
+ (map f z) )))
+@end group
+@end example
+
+Using a procedure bar defined as
+
+@example
+(define bar (let ((x 1)) (lambda (y) (set! x y) (+ x y))))
+@end example
+
+is slower than using a procedure bar defined as
+
+@example
+@group
+(define *bar-x* 1)
+(define bar (lambda (y) (set! *bar-x* y) (+ *bar-x* y)))
+@end group
+@end example
+
+since the former definition contains a non-liftable lambda-term.
+
+@item
+Try to minimize the amount of consing in the speed-critical program
+fragments, that is, a number of applications of cons, list, @t{map},
+quasiquote (`) and vector->list during the time program is running.
+@samp{cons} (called also by @samp{list}, @samp{map} and
+@samp{quasiquote}) is translated into a C call to an internal cons
+procedure of the SCM interpreter. Excessive consing also means that the
+garbage collection happens more often. Do @code{(verbose 3)} to see the
+amount of time used by garbage collection while your program is running.
+
+Try to minimize the amount of creating new vectors, strings and symbols
+in the speed-critical program frgaments, that is, a number of
+applications of @t{make-vector}, @t{vector}, @t{list->vector},
+@t{make-string}, @t{string-append}, *@t{->string}, @t{string->symbol}.
+Creating such objects takes typically much more time than consing.
+
+@item
+The Scheme iteration construction @samp{do} is compiled directly into
+the C iteration construction @samp{for}. We can expect that the C compiler
+has some knowledge about @samp{for} in the optimization stage, thus it is
+probably faster to use @samp{do} for iteration than non-mutual tailrecursion
+(which is recognized by hobbit as such and is compiled into a jump to a
+beginning of a procedure) and certainly much faster than
+non-tail-recursion or mutual tailrecursion (the latter is not recognized
+by hobbit as such).
+
+@item
+Declare small nonrecursive programs which do not contain
+let-s or lambdaterms as being inlinable.
+
+Declare globally defined variables which are never @t{set!} or redefined
+and whose value is a small integer, character or a boolean,
+as being inlinable. @xref{Hobbit Options}.
+
+@item
+If possible, declare vectors as being stable.
+@xref{Hobbit Options, Speeding up vectors}.
+This gives a minor improvement in speed.
+
+@item
+If possible, declare critical global vars as being uninterned.
+@xref{Hobbit Options, Speeding up and hiding certain global variables}.
+This gives a minor improvement in speed. Declare the global variables
+which are never @t{set!} and have an (unchanged) numeric or boolean
+value as being inlined. @xref{Hobbit Options}.
+@end enumerate
+
+In addition, take the following into account:
+
+@itemize @bullet
+@item
+When using the C compiler to compile the C code output by hobbit, always
+use strong optimizations (eg. @samp{cc -xO3} for cc on Sun, @samp{gcc
+-O2} or @samp{gcc -O3} for gcc). Hobbit does not attempt to do
+optimizations of the kind we anticipate from the C compiler, therefore
+it often makes a big difference if the C compiler is run with a strong
+optimization flag or not.
+
+@item
+hobbit does not give proper tailrecursion behaviour for mutual
+tailrecursion (foo calling bar, bar calling foo tailrecursively).
+
+Hobbit guarantees proper tailrecursive behaviour for non-mutual
+tailrecursion (foo calling foo tailrecursively), provided that
+foo is not redefined anywhere and that foo is not a local function which
+occurs also in a non-function and non-clonable-HOP-argument position
+(i.e. cases 3 and 6 above).
+@end itemize
+@end enumerate
+
+
+
+@node Performance of Compiled Code, Principles of Compilation, The Language Compiled, Top
+@chapter Performance of Compiled Code
+
+
+@menu
+* Gain in Speed::
+* Benchmarks::
+* Benchmark Sources::
+@end menu
+
+@node Gain in Speed, Benchmarks, Performance of Compiled Code, Performance of Compiled Code
+@section Gain in Speed
+
+The author has so far compiled and tested a number of large programs
+(theorem provers for various logics and hobbit itself).
+
+The speedup for the provers was between 25 and 40 times for various
+provable formulas. Comparison was made between the provers being
+interpreted and compiled with @samp{gcc -O2 -DRECKLESS} on Sparcstation
+ELC in both cases.
+
+The provers were written with care to make the compiled version run fast.
+They do not perform excessive consing and they perform very little
+arithmetic.
+
+According to experiments made by A. Jaffer, the compiled form of the
+example program @file{pi.scm} was approximately 11 times faster than the
+interpreted form.
+
+As a comparison, his hand-coded C program for the same algorithm of
+computing pi was about 12 times faster than the interpreted form.
+@file{pi.scm} spends most of of its time in immediate arithmetics,
+@t{vector-ref} and @t{vector-set!}.
+
+P. Kelloma"ki has reported a 20-fold speedup for his generic scheme
+debugger. T. Moore has reported a 16-fold speedup for a large gate-level
+IC optimizer.
+
+Self-compilation speeds Hobbit up only ca 10 times.
+
+However, there are examples where the code compiled by hobbit
+runs actually slower than the same code running under interpreter:
+this may happen in case the speed of the code relies on non-liftable
+closures and proper mutual tailrecursion. See for example the
+closure-intensive benchmark CPSTAK in the following table.
+
+@page
+@node Benchmarks, Benchmark Sources, Gain in Speed, Performance of Compiled Code
+@section Benchmarks
+
+We will present a table with the performance of three scheme systems on
+a number of benchmarks: interpreted SCM, byte-compiled VSCM and
+hobbit-compiled code. The upper 13 benchmarks of the table are the
+famous Gabriel benchmarks (originally written for lisp) modified for
+scheme by Will Clinger. The lower five benchmarks of the table are
+proposed by other people. @dfn{Selfcompile} is the self-compile time
+of Hobbit.
+
+
+Hobbit performs well on most of the benchmarks except
+CPSTAK and CTAK: CPSTAK is a closure-intensive tailrecursive
+benchmark and CTAK is a continuations-intensive benchmark.
+Hobbit performs extremely well on these benchmarks which essentially
+satisfy the criterias for well-optimizable code outlined in the
+section 6 above.
+
+FFT is real-arithmetic-intensive.
+
+All times are in seconds.
+
+SCM 4c0(U) and 1.1.5*(U) (the latter is the newest version of VSCM)
+are compiled and run by Matthias Blume on a DecStation 5000 (Ultrix).
+VSCM is a bytecode-compiler using continuation-passing style, and is well
+optimized for continuations and closures.
+
+SCM 4e2(S) and Hobbit4b(S) compiled (with @samp{cc -xO3}) and run by
+Tanel Tammet on a Sun SS10 (lips.cs.chalmers.se). Hobbit is a
+Scheme-to-C compiler for SCM, the code it produces does not do any
+checking. SCM and hobbit are not optimized for continuations. Hobbit
+is not optimized for closures and proper mutual tailrecursion.
+
+SCM and Hobbit benchmarks were run giving ca 8 MB of free heap space
+before each test.
+
+@example
+@group
+Benchmark |SCM 4c0(U) 1.1.5*(U)| SCM 4e2(S) Hobbit4b(S)
+----------------|------------------------------------------------
+Deriv | 3.40 3.86 | 2.9 0.18
+Div-iter | 3.45 2.12 | 2.6 0.083
+Div-rec | 3.45 2.55 | 3.5 0.42
+TAK | 1.81 1.71 | 1.4 0.018
+TAKL |14.50 11.32 | 13.8(1.8 in gc) 0.13
+TAKR | 2.20 1.64 | 1.7 1.5 0.018
+Destruct | ? ? | 7.4(1.8 in gc) 0.18
+Boyer | ? ? | 27.(3.8 in gc) 1.9
+CPSTAK | 2.72 2.64 | 2.0 1.92 3.46(2.83 in gc)
+CTAK |31.0 4.11 | memory memory
+CTAK(7 6 1) | ? ? | 0.83 0.74
+FFT |12.45 15.7 | 11.4 10.8 1.0
+Puzzle | 0.28 0.41 | 0.46(0.22 gc) 0.03
+----------------------------------------------------------------
+(recfib 25) | ? ? | 4.1 0.079
+(recfib 30) | ? ? | 55. (10.in gc) 0.87
+(pi 300 3) | ? ? | 7.4 0.46
+(hanoi 15) | ? ? | 0.68 0.007
+(hanoi 20) | ? ? | 31. (9. in gc) 0.2
+----------------------------------------------------------------
+@end group
+@end example
+
+@page
+@node Benchmark Sources, , Benchmarks, Performance of Compiled Code
+@section Benchmark Sources
+@subheading A selection of (smaller) benchmark sources
+
+@menu
+* Destruct::
+* Recfib::
+* div-iter and div-rec::
+* Hanoi::
+* Tak::
+* Ctak::
+* Takl::
+* Cpstak::
+* Pi::
+@end menu
+
+@node Destruct, Recfib, Benchmark Sources, Benchmark Sources
+@subsection Destruct
+
+@example
+@group
+;;;; Destructive operation benchmark
+(define (destructive n m)
+ (let ((l (do ((i 10 (- i 1))
+ (a '() (cons '() a)))
+ ((= i 0) a))))
+ (do ((i n (- i 1)))
+ ((= i 0))
+ (if (null? (car l))
+ (do ((l l (cdr l)))
+ ((null? l))
+ (or (car l) (set-car! l (cons '() '())))
+ (append! (car l) (do ((j m (- j 1))
+ (a '() (cons '() a)))
+ ((= j 0) a))))
+ (do ((l1 l (cdr l1))
+ (l2 (cdr l) (cdr l2)))
+ ((null? l2))
+ (set-cdr! (do ((j (quotient (length (car l2)) 2) (- j 1))
+ (a (car l2) (cdr a)))
+ ((zero? j) a)
+ (set-car! a i))
+ (let ((n (quotient (length (car l1)) 2)))
+ (cond ((= n 0) (set-car! l1 '()) (car l1))
+ (else (do ((j n (- j 1))
+ (a (car l1) (cdr a)))
+ ((= j 1)
+ (let ((x (cdr a)))
+ (set-cdr! a '()) x))
+ (set-car! a i)))))))))))
+;; call: (destructive 600 50)
+@end group
+@end example
+
+@need 1500
+@node Recfib, div-iter and div-rec, Destruct, Benchmark Sources
+@subsection Recfib
+
+@example
+@group
+(define (recfib x)
+ (if (< x 2)
+ x
+ (+ (recfib (- x 1))
+ (recfib (- x 2)))))
+@end group
+@end example
+
+@need 4000
+@node div-iter and div-rec, Hanoi, Recfib, Benchmark Sources
+@subsection div-iter and div-rec
+
+@example
+@group
+;;;; Recursive and iterative benchmark divides by 2 using lists of ()'s.
+(define (create-n n)
+ (do ((n n (- n 1))
+ (a '() (cons '() a)))
+ ((= n 0) a)))
+(define *ll* (create-n 200))
+(define (iterative-div2 l)
+ (do ((l l (cddr l))
+ (a '() (cons (car l) a)))
+ ((null? l) a)))
+(define (recursive-div2 l)
+ (cond ((null? l) '())
+ (else (cons (car l) (recursive-div2 (cddr l))))))
+(define (test-1 l)
+ (do ((i 300 (- i 1))) ((= i 0))
+ (iterative-div2 l)
+ (iterative-div2 l)
+ (iterative-div2 l)
+ (iterative-div2 l)))
+(define (test-2 l)
+ (do ((i 300 (- i 1))) ((= i 0))
+ (recursive-div2 l)
+ (recursive-div2 l)
+ (recursive-div2 l)
+ (recursive-div2 l)))
+;; for the iterative test call: (test-1 *ll*)
+;; for the recursive test call: (test-2 *ll*)
+@end group
+@end example
+
+@need 1000
+@node Hanoi, Tak, div-iter and div-rec, Benchmark Sources
+@subsection Hanoi
+
+@example
+@group
+;;; C optimiser should be able to remove the first recursive call to
+;;; move-them. But Solaris 2.4 cc, gcc 2.5.8, and hobbit don't.
+(define (hanoi n)
+ (letrec ((move-them
+ (lambda (n from to helper)
+ (if (> n 1)
+ (begin
+ (move-them (- n 1) from helper to)
+ (move-them (- n 1) helper to from))))))
+ (move-them n 0 1 2)))
+@end group
+@end example
+
+@page
+@node Tak, Ctak, Hanoi, Benchmark Sources
+@subsection Tak
+
+@example
+@group
+;;;; A vanilla version of the TAKeuchi function
+(define (tak x y z)
+ (if (not (< y x))
+ z
+ (tak (tak (- x 1) y z)
+ (tak (- y 1) z x)
+ (tak (- z 1) x y))))
+;; call: (tak 18 12 6)
+@end group
+@end example
+
+@need 2000
+@node Ctak, Takl, Tak, Benchmark Sources
+@subsection Ctak
+
+@example
+@group
+;;;; A version of the TAK function that uses continuations
+(define (ctak x y z)
+ (call-with-current-continuation
+ (lambda (k)
+ (ctak-aux k x y z))))
+
+(define (ctak-aux k x y z)
+ (cond ((not (< y x)) (k z))
+ (else (call-with-current-continuation
+ (ctak-aux
+ k
+ (call-with-current-continuation
+ (lambda (k) (ctak-aux k (- x 1) y z)))
+ (call-with-current-continuation
+ (lambda (k) (ctak-aux k (- y 1) z x)))
+ (call-with-current-continuation
+ (lambda (k) (ctak-aux k (- z 1) x y))))))))
+
+(define (id x) x)
+
+(define (mb-test r x y z)
+ (if (zero? r)
+ (ctak x y z)
+ (id (mb-test (- r 1) x y z))))
+;;; call: (ctak 18 12 6)
+@end group
+@end example
+
+@need 2000
+@node Takl, Cpstak, Ctak, Benchmark Sources
+@subsection Takl
+
+@example
+@group
+;;;; The TAKeuchi function using lists as counters.
+(define (listn n)
+ (if (not (= 0 n))
+ (cons n (listn (- n 1)))
+ '()))
+
+(define l18 (listn 18))
+(define l12 (listn 12))
+(define l6 (listn 6))
+
+(define (mas x y z)
+ (if (not (shorterp y x))
+ z
+ (mas (mas (cdr x) y z)
+ (mas (cdr y) z x)
+ (mas (cdr z) x y))))
+
+(define (shorterp x y)
+ (and (pair? y) (or (null? x) (shorterp (cdr x) (cdr y)))))
+;; call: (mas l18 l12 l6)
+@end group
+@end example
+
+@need 2000
+@node Cpstak, Pi, Takl, Benchmark Sources
+@subsection Cpstak
+
+@example
+@group
+;;;; A continuation-passing version of the TAK benchmark.
+(define (cpstak x y z)
+ (define (tak x y z k)
+ (if (not (< y x))
+ (k z)
+ (tak (- x 1)
+ y
+ z
+ (lambda (v1)
+ (tak (- y 1)
+ z
+ x
+ (lambda (v2)
+ (tak (- z 1)
+ x
+ y
+ (lambda (v3)
+ (tak v1 v2 v3 k)))))))))
+ (tak x y z (lambda (a) a)))
+;;; call: (cpstak 18 12 6)
+@end group
+@end example
+
+@need 4000
+@node Pi, , Cpstak, Benchmark Sources
+@subsection Pi
+
+@example
+@group
+(define (pi n . args)
+ (let* ((d (car args))
+ (r (do ((s 1 (* 10 s))
+ (i 0 (+ 1 i)))
+ ((>= i d) s)))
+ (n (+ (quotient n d) 1))
+ (m (quotient (* n d 3322) 1000))
+ (a (make-vector (+ 1 m) 2)))
+ (vector-set! a m 4)
+ (do ((j 1 (+ 1 j))
+ (q 0 0)
+ (b 2 (remainder q r)))
+ ((> j n))
+ (do ((k m (- k 1)))
+ ((zero? k))
+ (set! q (+ q (* (vector-ref a k) r)))
+ (let ((t (+ 1 (* 2 k))))
+ (vector-set! a k (remainder q t))
+ (set! q (* k (quotient q t)))))
+ (let ((s (number->string (+ b (quotient q r)))))
+ (do ((l (string-length s) (+ 1 l)))
+ ((>= l d) (display s))
+ (display #\0)))
+ (if (zero? (modulo j 10)) (newline) (display #\ )))
+ (newline)))
+@end group
+@end example
+
+
+@node Principles of Compilation, About Hobbit, Performance of Compiled Code, Top
+@chapter Principles of Compilation
+
+@menu
+* Macro-Expansion and Analysis:: Pass 1
+* Building Closures:: Pass 2
+* Lambda-lifting:: Pass 3
+* Statement-lifting:: Pass 4
+* Higher-order Arglists:: Pass 5
+* Typing and Constants:: Pass 6
+@end menu
+
+@node Macro-Expansion and Analysis, Building Closures, Principles of Compilation, Principles of Compilation
+@section Expansion and Analysis
+
+
+@enumerate
+@item
+Macros defined by defmacro and all the quasiquotes
+are expanded and compiled into equivalent form without macros
+and quasiquotes.
+
+For example, `(a , x) will be converted to (cons 'a (cons x '())).
+
+@item
+Define-s with the nonessential syntax like
+
+@example
+(define (foo x) @dots{})
+@end example
+
+are converted to @t{define}s with the essential syntax
+
+@example
+(define foo (lambda (x) @dots{}))
+@end example
+
+Non-top-level @t{define}s are converted into equivalent
+@t{letrec}-s.
+
+@item
+Variables are renamed to avoid name clashes, so that any local
+variable may have a whole procedure as its scope. This renaming
+also converts let-s to let*-s. Variables which do not introduce
+potential name clashes are not renamed. For example,
+
+@example
+@group
+(define (foo x y)
+ (let ((x y)
+ (z x))
+ (let* ((x (+ z x)))
+ x)))
+@end group
+@end example
+
+is converted to
+
+@example
+@group
+(define foo
+ (lambda (x y)
+ (let* ((x__1 y)
+ (z x)
+ (x__2 (+ z x__1)))
+ x__2)))
+@end group
+@end example
+
+@item
+In case the set of procedures defined in one @t{letrec} is actually not
+wholly mutually recursive (eg, f1 calls f2, but f2 does not call f1, or
+there are three procedures, f1, f2, f3 so that f1 and f2 are mutually
+recursive but f3 is not called from f1 or f2 and it does not call them,
+etc), it is possible to minimize the number of additional variables
+passed to procedures.
+
+Thus @t{letrec}-s are split into ordered chunks using dependency
+analysis and topological sorting, to reduce the number of mutually
+passed variables. Wherever possible, @t{letrec}-s are replaced by
+@t{let*}-s inside these chunks.
+
+
+@item
+Normalization is performed. This converts a majority of scheme
+control procedures like cond, case, or, and into equivalent
+terms using a small set of primitives. New variables may be
+introduced in this phase.
+
+In case a procedure like or or and occurs in the place where its value
+is treated as a boolean (eg. first argument of if), it is converted
+into an analogous boolean-returning procedure, which will finally
+be represented by an analogous C procedure (eg. || or &&).
+
+Associative procedures are converted into structures of corresponding
+nonassociative procedures. List is converted to a structure of cons-s.
+
+Map and @t{for-each} with more than two arguments are converted into an
+equivalent do-cycle. @t{map}-s and @t{for-each}-s with two arguments are
+treated as if they were defined in the compiled file -- the definitions
+@t{map1} and @t{for-each1} are automatically included, if needed.
+
+There is an option in @file{hobbit.scm} to make all @t{map}-s and
+@t{for-each}-s be converted into equivalent do-loops, avoiding the use
+of @t{map1} and/or @t{for-each1} altogether.
+
+
+@item
+Code is analysed for determining which primitive names and
+compiled procedure names are assumed to be redefinable.
+
+@item
+Analysing HOP clonability: hobbit will find a list of clonable
+HOP-s with information about higher-order arguments.
+
+Criterias for HOP clonability are given in the section 6.4.
+
+
+@item
+Analysis of liftability: hobbit will determine which lambda-terms
+have to be built as real closures (implemented as a vector where the
+first element is a pointer to a function and the rest contain values
+of environment variables or environment blocks of surrounding code)
+and which lambda-terms are liftable.
+
+Liftability analysis follows the criterias given in section 6.5 and
+6.6.
+@end enumerate
+
+
+@node Building Closures, Lambda-lifting, Macro-Expansion and Analysis, Principles of Compilation
+@section Building Closures
+
+
+Here Hobbit produces code for creating real closures for all the
+lambda-terms which are not marked as being liftable by the previous
+liftability analysis.
+
+Global variables (eg x-glob) are translated as pointers (locations) to
+SCM objects and used via a fetch: *x_glob (or a fetch
+macro GLOBAL(x-glob) which translates to *x_glob).
+
+While producing closures hobbit tries to minimize the indirection
+levels necessary. Generally a local variable x may have to be translated
+to an element of a vector of local variables built in the procedure
+creating x. If x occurs in a non-liftable closure, the whole vector
+of local variables is passed to a closure.
+
+Such a translation using a local vector will only take place if either x
+is @t{set!} inside a non-liftable lambda-term or x is a name of a
+recursively defined non-liftable function, and the definition of x is
+irregular. The definition of x is irregular if x is given the
+non-liftable recursive value @var{t} by extra computation, eg as
+
+@example
+(set! x (let ((u 1)) (lambda (y) (display u) (x (+ u 1)))))
+@end example
+
+and not as a simple lambdaterm:
+
+@example
+(set! x (lambda (y) (display x) (x (+ y 1))))
+@end example
+
+In all the other cases a local scheme variable x is translated
+directly to a local C variable x having the type SCM (a 32-bit
+integer). If such an x occurs in a non-liftable closure, then
+only its value is passed to a closure via the closure-vector.
+In case the directly-translated variable x is passed to a liftable
+lambda-term where it is @t{set!}, then x is passed indirectly by
+using its address &x. In the lifted lambda-term it is then accessed via *.
+
+If all the variables x1, @dots{}, xn created in a procedure can be
+translated directly as C variables, then the procedure does not create a
+special vector for (a subset of) local variables.
+
+An application (foo @dots{}) is generally translated to C by an internal
+apply of the SCM interpreter:
+apply(GLOBAL(foo), @dots{}). Using an internal apply is much slower than
+using direct a C function call, since:
+
+@itemize @bullet
+@item
+there is an extra fetch by GLOBAL(foo),
+@item
+internal apply performs some computations,
+@item
+the arguments of foo are passed as a list constructed during
+ application: that is, there is a lot of expensive consing every
+ time foo is applied via an internal apply.
+@end itemize
+
+However, in case foo is either a name of a non-redefined primitive or a
+name of a non-redefined liftable procedure, the application is
+translated to C directly without the extra layer of calling apply:
+foo(@dots{}).
+
+Sometimes lambda-lifting generates the case that some variable
+x is accessed not directly, but by *x. See the next section.
+
+Undefined procedures are assumed to be defined via interpreter
+and are called using an internal apply.
+
+@node Lambda-lifting, Statement-lifting, Building Closures, Principles of Compilation
+@section Lambda-lifting
+
+
+When this pass starts, all the real (nonliftable) closures have been
+translated to closure-creating code. The remaining lambda-terms
+are all liftable.
+
+Lambda-lifting is performed. That is, all procedures defined inside
+some other procedure (eg. in @t{letrec}) and unnamed lambda-terms are
+made top-level procedure definitions. Any N variables not bound in such
+procedures which were bound in the surrounding procedure are given as
+extra N first parameters of the procedure, and whenever the procedure is
+called, the values of these variables are given as extra N first
+arguments.
+
+For example:
+
+@example
+@group
+(define foo
+ (lambda (x y)
+ (letrec ((bar (lambda (u) (+ u x))))
+ (bar y) )))
+@end group
+@end example
+
+is converted to
+
+@example
+@group
+(define foo
+ (lambda (x y)
+ (foo-fn1 x y) ))
+
+(define foo-fn1
+ (lambda (x u)
+ (+ u x) ))
+@end group
+@end example
+
+The case of mutually recursive definitions in @t{letrec} needs special
+treatment -- all free variables in mutually recursive funs have, in
+general, to be passed to each of those funs. For example, in
+
+@example
+@group
+(define (foo x y z i)
+ (letrec ((f1 (lambda (u) (if x (+ (f2 u) 1))))
+ (f2 (lambda (v) (if (zero? v) 1 (f1 z)))) )
+ (f2 i) ))
+@end group
+@end example
+
+the procedure f1 contains a free variable x and the procedure f2
+contains a free variable z. Lambda-lifted f1 and f2 must
+each get both of these variables:
+
+@example
+@group
+(define (foo x y z i)
+ (foo-fn2 x z i) )
+
+(define foo-fn1
+ (lambda (x z u) (if x (+ (foo-fn2 x z u) 1))) )
+
+(define foo-fn2
+ (lambda (x z v) (if (zero? v) 1 (foo-fn1 x z z))) )
+@end group
+@end example
+
+Recall that hobbit has already done dependency analysis and has
+split the original @t{letrec} into smaller chunks according to this
+analysis: see pass 1.
+
+Whenever the value of some free variable is modified by @t{set!} in
+the procedure, this variable is passed by reference instead.
+This is not directly possible in scheme, but it is possible in C.
+
+@example
+@group
+(define foo
+ (lambda (x y z)
+ (letrec ((bar (lambda (u) (set! z (+ u x z)))))
+ (bar y)
+ z)))
+@end group
+@end example
+
+is converted to incorrect scheme:
+
+@example
+@group
+(define foo
+ (lambda (x y z)
+ (foo-fn1 x (**c-adr** z) y)
+ z))
+
+(define foo-fn1
+ (lambda (x (**c-adr** z) u)
+ (set! (**c-fetch** z) (+ u x (**c-fetch** z))) ))
+@end group
+@end example
+
+The last two will finally be compiled into correct C as:
+
+@example
+@group
+SCM foo(x, y, z)
+SCM x, y, z;
+@{
+ foo_fn1(x, &z, y);
+ return z;
+@}
+
+SCM foo_fn1(x, z, u)
+SCM x, u;
+SCM *z;
+@{
+ return (*z = (u + x) + *z);
+@}
+@end group
+@end example
+
+
+
+@node Statement-lifting, Higher-order Arglists, Lambda-lifting, Principles of Compilation
+@section Statement-lifting
+
+As the scheme do-construction is compiled into C for, but for cannot
+occur in all places in C (it is a statement), then if the do in a
+scheme procedure occurs in a place which will not be a statement
+in C, the whole do-term is lifted out into a new top-level
+procedure analogously to lambda-lifting. Any statement-lifted
+parts of some procedure foo are called foo_aux@var{n}, where @var{n}
+is a number.
+
+The special C-ish procedure **return** is pushed into a scheme term as far
+as possible to extend the scope of statements in the resulting
+C program. For example,
+
+@example
+@group
+(define foo
+ (lambda (x y)
+ (if x (+ 1 y) (+ 2 y)) ))
+@end group
+@end example
+
+is converted to
+
+@example
+@group
+(define foo
+ (lambda (x y)
+ (if x (**return** (+ 1 y)) (**return** (+ 2 y))) ))
+@end group
+@end example
+
+Immediate tailrecursion (foo calling foo tailrecursively) is
+recognized and converted into an assignment of new values to args and
+a jump to the beginning of the procedure body.
+
+
+@node Higher-order Arglists, Typing and Constants, Statement-lifting, Principles of Compilation
+@section Higher-order Arglists
+
+All procedures taking a list argument are converted into ordinary
+non-list taking procedures and they are called with the list-making
+calls inserted. For example,
+
+@example
+@group
+(define foo
+ (lambda (x . y)
+ (cons x (reverse y)) ))
+@end group
+@end example
+
+is converted to
+
+@example
+@group
+(define foo
+ (lambda (x y)
+ (cons x (reverse y)) ))
+@end group
+@end example
+
+and any call to foo will make a list for a variable y. For example,
+
+@example
+(foo 1 2 3)
+@end example
+
+is converted to
+
+@example
+(foo 1 (cons 2 (cons 3 '()))).
+@end example
+
+All higher-order procedure calls where an argument-term contains
+unbound variables will generate a new instance (provided it
+has not been created already) of this higher-order procedure,
+carrying the right amount of free variables inside to right
+places.
+
+For example, if there is a following definition:
+
+@example
+@group
+(define (member-if fn lst)
+ (if (fn (car lst))
+ lst
+ (member-if fn (cdr lst)) ))
+@end group
+@end example
+
+and a call
+
+@example
+(member-if (lambda (x) (eq? x y)) lst),
+@end example
+
+a new instance of member-if is created (if an analogous one
+has not been created before):
+
+@example
+@group
+(define (member-if_inst1 tmp fn lst)
+ (if (fn tmp (car lst))
+ lst
+ (member-if_inst1 tmp fn (cdr lst)) ))
+@end group
+@end example
+
+and the call is converted to
+
+@example
+(member-if_inst1 y foo lst)
+@end example
+
+and a top-level @t{define}
+
+@example
+(define (foo y x) (eq? x y))
+@end example
+
+In addition, if the higher-order procedure is to be exported,
+an additional instance is created, which uses apply to
+call all argument-procedures, assuming they are defined via interpreter.
+The exportable higher-order procedure will have a name @var{fun}_exporthof,
+where @var{fun} is the name of the original procedure.
+
+
+@node Typing and Constants, , Higher-order Arglists, Principles of Compilation
+@section Typing and Constants
+
+All C<->Scheme conversions for immediate objects like numbers,
+booleans and characters are introduced. Internal apply
+is used for undefined procedures. Some optimizations are performed
+to decrease the amount of C<->Scheme object conversions.
+
+All vector, pair and string constants are replaced by new
+variables. These variables are instantiated to the right
+values by init_@var{foo*}.
+
+Procedures foo which are to be exported (made accesible to the
+interpreter), and which have an arity different from one of the
+following five templates: x, (), (x), (x y), (x y z), are made
+accessible via an additional procedure foo_wrapper taking a single
+list argument.
+
+@subheading C Code Generation
+
+More or less straightforward.
+
+The type conversion between C objects and immediate Scheme objects of
+the type boolean, char and num is performed by macros. The scheme
+object @t{'()} is represented by the macro object EOL.
+
+@subheading Intermediate files
+
+Experiment yourself by defining:
+
+@example
+(define *build-intermediate-files* #t)
+@end example
+
+instead of the default:
+
+@example
+(define *build-intermediate-files* #f).
+@end example
+
+
+@node About Hobbit, , Principles of Compilation, Top
+@chapter About Hobbit
+
+@menu
+* The Aims of Developing Hobbit::
+* Manifest::
+* Author and Contributors::
+* Future Improvements::
+* Release History::
+@end menu
+
+@node The Aims of Developing Hobbit, Manifest, About Hobbit, About Hobbit
+@section The Aims of Developing Hobbit
+
+@enumerate
+@item
+Producing maximally fast C code from simple scheme code.
+
+By @dfn{simple} we mean code which does not rely on procedures
+returning procedures (closures) and nontrivial forms of
+higher-order procedures. All the latter are also compiled,
+but the optimizations specially target simple code fragments.
+Hobbit performs global optimization in order to locate such fragments.
+
+@item
+Producing C code which would preserve as much original scheme
+code structure as possible, to enable using the output C code
+by a human programmer (eg. for introducing special optimizations
+possible in C). Also, this will hopefully help the C compiler
+to find better optimizations.
+@end enumerate
+
+
+@node Manifest, Author and Contributors, The Aims of Developing Hobbit, About Hobbit
+@section Manifest
+
+@multitable @columnfractions .2 .8
+@item @file{hobbit.scm}
+@tab the hobbit compiler.
+@item @file{scmhob.scm}
+@tab the file defining some additional procedures recognized
+by hobbit as primitives. Use it with the interpreter only.
+@item @file{scmhob.h}
+@tab the common headerfile for hobbit-compiled C files.
+@item @file{hobbit.texi}
+@tab documentation for hobbit.
+@end multitable
+
+
+@node Author and Contributors, Future Improvements, Manifest, About Hobbit
+@section Author and Contributors
+
+@quotation
+Tanel Tammet@*
+Department of Computing Science@*
+Chalmers University of Technology@*
+University of Go"teborg@*
+S-41296 Go"teborg Sweden
+@end quotation
+
+A. Jaffer (jaffer @@ alum.mit.edu), the author of SCM, has been of major
+help with a number of suggestions and hacks, especially concerning the
+interface between compiled code and the SCM interpreter.
+
+Several people have helped with suggestions and detailed bug reports,
+e.g. David J. Fiander (davidf@@mks.com), Gordon Oulsnam
+(STCS8004@@IRUCCVAX.UCC.IE), Pertti Kelloma"ki (pk@@cs.tut.fi),
+Dominique de Waleffe (ddw2@@sunbim.be) Terry Moore (tmm@@databook.com),
+Marshall Abrams (ab2r@@midway.uchicago.edu). Georgy K. Bronnikov
+(goga@@bronnikov.msk.su), Bernard Urban (Bernard.URBAN@@meteo.fr),
+Charlie Xiaoli Huang, Tom Lord (lord@@cygnus.com),
+NMICHAEL@@us.oracle.com, Lee Iverson (leei@@ai.sri.com), Burt
+Leavenworth (EDLSOFT@@aol.com).
+
+
+@page
+@node Future Improvements, Release History, Author and Contributors, About Hobbit
+@section Future Improvements
+
+@enumerate
+@item
+Optimisations:
+
+@itemize
+@item
+the calls to internal apply: we'd like to avoid the excessive consing of
+always building the list of arguments.
+@item
+speeding up the creation of a vector for assignable closure-variables
+@item
+several peephole optimisations.
+@end itemize
+
+@item
+Improve Variable creation and naming to avoid C function name clashes.
+
+@item
+Report 4 macros.
+
+@item
+Better error-checking.
+
+@item
+Better liftability analysis.
+
+@item
+More tailrecursion recognition.
+
+@item
+Better numeric optimizations.
+
+@item
+Fast real-only arithmetics: $eqv, $=, $>, $+, $*, etc.
+@end enumerate
+
+
+@node Release History, , Future Improvements, About Hobbit
+@section Release History
+
+@quotation
+[In February 2002, hobbit5x was integrated into the SCM distribution.
+Changes since then are recorded in @file{scm/ChangeLog}.]
+@end quotation
+
+@table @asis
+@item hobbit4d:
+@itemize @bullet
+@item
+the incorrect translation of char>?, char-ci>?, char>=?, char-ci>=?
+string>?, string-ci>?, string-ci>=?, string>=? reported by
+Burt Leavenworth (EDLSOFT@@aol.com) was fixed.
+@item
+the name clash bug for new variables new_varN occurring in
+non-liftable closures (reported by Lee Iverson (leei@@ai.sri.com))
+was fixed.
+@item
+the major COPYRIGHT change: differently from all the previous
+versions of Hobbit, hobbit4d is Free Software.
+@end itemize
+
+@item hobbit4c:
+@itemize @bullet
+@item
+a liftability-analysis bug for @t{for-each} and @t{map} reported
+by Lee Iverson (leei@@ai.sri.com) has been fixed.
+@item
+The output C code does not contain the unnecessary ;-s on
+separate lines any more.
+@end itemize
+
+@item hobbit4b:
+The following bugs have been fixed:
+@itemize @bullet
+@item
+Erroneous treatment of [ and ] inside symbols,
+reported by A. Jaffer (jaffer @@ alum.mit.edu).
+@item
+A bug in the liftability analysis,
+reported by A. Jaffer (jaffer @@ alum.mit.edu).
+@item
+A bug occurring in case arguments are evaluated right-to-left,
+which happens with Hobbit compiled by gcc on Linux.
+Reported and patched by George K. Bronnikov (goga@@bronnikov.msk.su)
+@item
+A closure-building bug sometimes leading to a serious loss of
+efficiency (liftability not recognized),
+reported by NMICHAEL@@us.oracle.com.
+@item
+A bug in the liftability analysis (non-liftable lambda-term
+inside a liftable lambda-term)
+reported by Lee Iverson (leei@@ai.sri.com)
+@end itemize
+
+@item hobbit4a:
+Several bugs found in version4x are fixed.
+
+@item hobbit4x (not public):
+@itemize @bullet
+@item
+A major overhaul: Hobbit is now able to compile full scheme,
+not just the fast liftable-clonable fragment.
+
+The optimizations done by the earlier versions are preserved.
+
+@item
+Numerous bugs found in earlier versions have been fixed.
+@end itemize
+
+@item hobbit3d:
+bugs found in the version 3c are fixed.
+
+@item hobbit3c:
+@itemize @bullet
+@item
+the form
+
+@example
+(define foo (let ((x1 <t1>) @dots{} (xn <tn>)) (lambda @dots{})))
+@end example
+
+is now supported for all terms <ti> except procedures defined
+in the compiled files.
+@item
+macros are partially supported by doing a preprocessing pass using the
+procedures pprint-filter-file and defmacro:expand* defined
+in slib.
+@item
+the file @file{scmhob.scm} defining hobbit-recognized nonstandard
+procedures is created.
+@item
+the documentation is improved (thanks go to Aubrey for suggestions).
+@end itemize
+
+@item hobbit3b:
+@itemize @bullet
+@item
+Aubrey fixed some problems with the version 3.
+@item
+It is now OK to define procedures "by name" on top level.
+@item
+It is now OK to apply "apply", etc to procedures defined
+in the compiled file. Compiled procedures may now be passed
+to procedures not defined but still called in the compiled files.
+@end itemize
+
+@item hobbit3:
+@itemize @bullet
+@item
+Generic arithmetic supported by SCM (exact and inexact reals,
+bignums) is made available.
+@item
+The #. special syntactic form of SCM is made available.
+@item
+Procedures with chars are compiled open-coded, making them faster.
+@item
+The bug concerning strings containing an embedded \nl char
+is corrected (thanks to Terry Moore, (tmm@@databook.com)).
+@item
+The special declaration compile-stable-vectors for optimizing
+vector access is introduced.
+@item
+Source code may contain top-level computations, top-level
+loads are ignored.
+@item
+The bug causing "or" to (sometimes) lose tailrecursiveness is corrected.
+@item
+Hobbit now allows the following very special form:
+
+@example
+(define foo (let ((bar bar)) (lambda @dots{})))
+@end example
+
+Notice @code{(bar bar)}. See the section 5 above. It will produce wrong
+code if bar is redefined.
+
+There were several versions of the 2-series, like 2.x, which were
+not made public. The changes introduced are present in the version 3.
+@end itemize
+
+@item hobbit2:
+@itemize @bullet
+@item
+The following bitwise procedures in the scheme library file
+@file{logical.scm} are compiled directly to C
+(Scheme library funs in the upper row, C ops below):
+
+@example
+@group
+logand logior logxor lognot logsleft logsright
+ & | ^ ~ << >>
+@end group
+@end example
+
+Notice that the procedures @t{logsleft}, @t{logsright} are @b{NOT} in
+the the library file @file{logical.scm}: the universal procedure @t{ash}
+is instead. Procedures @t{ash}, @t{logcount}, @t{integer-length},
+@t{integer-expt}, @t{bit-extract} in @file{logical.scm} are not
+recognized by hobbit.
+@end itemize
+
+@item hobbit1a3 (not public):
+@itemize @bullet
+@item
+the @t{letrec}-sorting bug often resulting in not recognizing procedures
+defined in @t{letrec} (or local @t{define}s) has been corrected.
+@item
+the primitives @t{string} and @t{vector} are now compiled correctly.
+@end itemize
+
+@item hobbit1a2 (not public):
+@itemize @bullet
+@item
+any fixed arity procedure (including primitives) may be passed to any
+higher-order procedure by name. Variable arity procedures (eg
+primitives @t{list}, @t{+}, @t{display} and defined funs like
+@code{(define (foo x . y) x)}) must not be passed to new defined
+higher-order funs.
+@item
+some optimizations have been introduced for calls to @t{map}
+and @t{for-each}.
+@item
+(map list x y) bug has been corrected.
+@item
+Corrected self-compilation name clash between call_cc and call-cc.
+@end itemize
+
+@item hobbit1a1 (not public):
+@itemize @bullet
+@item
+named let is supported.
+@item
+the inlining bug is fixed: all procedures declared to be
+inlined are fully inlined, except when the flag
+*full-inlining-flag* is defined as #f.
+@item
+the @t{letrec} (or in-procedure define) bug where local procedure
+names were not recognized, is fixed.
+@item
+documentation says explicitly that definitions like
+
+@example
+(define foo (let ((x 0)) (lambda (y) @dots{})))
+@end example
+
+are assumed to be closure-returning procedures and are prohibited.
+@item
+documentation allows more liberty with passing procedures to
+higher-order funs by dropping the general requirement that only unnamed
+lambda-terms may be passed. Still, primitives and list-taking
+procedures may not be passed by name.
+@item
+documentation prohibits passing lambda-terms with free variables to
+recursive calls of higher-order procedures in the definition of a
+higher-order procedure.
+@end itemize
+
+@item hobbit1:
+the first release
+@end table
+
+
+@contents
+@bye