1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 03:30:27 +02:00

Letrectify only on -O2; update docs

* doc/ref/api-evaluation.texi (Compilation): Document the -O options.
* doc/ref/api-modules.texi (Using Guile Modules): @@ docs refer to
  declarative modules.
  (Creating Guile Modules): Use when for 1-armed if.
  (Declarative Modules): Make implications of declarative bindings more
  explicit, and explicitly document ways to disable the optimization.
* module/language/tree-il/optimize.scm (tree-il-optimizations): Punt
  letrectification to -O2.
This commit is contained in:
Andy Wingo 2019-08-25 12:51:03 +02:00
parent 253cf3dc6f
commit 31cb10af81
3 changed files with 96 additions and 6 deletions

View file

@ -675,6 +675,17 @@ warnings include @code{unused-variable}, @code{unused-toplevel},
@code{arity-mismatch}, @code{format},
@code{duplicate-case-datum}, and @code{bad-case-datum}.
@item -O @var{opt}
@itemx --optimize=@var{opt}
@cindex optimizations, compiler
Enable or disable specific compiler optimizations; use @code{-Ohelp} for
a list of available options. The default is @code{-O2}, which enables
most optimizations. @code{-O1} is recommended if compilation speed is
more important than the speed of the compiled code. Pass
@code{-Ono-@var{opt}} to disable a specific compiler pass. Any number
of @code{-O} options can be passed to the compiler, with later ones
taking precedence.
@item -f @var{lang}
@itemx --from=@var{lang}
Use @var{lang} as the source language of @var{file}. If this option is omitted,

View file

@ -240,7 +240,8 @@ Refer to the binding named @var{binding-name} in module
Refer to the binding named @var{binding-name} in module
@var{module-name}. The binding must not have been exported by the
module. This syntax is only intended for debugging purposes or as a
last resort.
last resort. @xref{Declarative Modules}, for some limitations on the
use of @code{@@@@}.
@end deffn
@node Creating Guile Modules
@ -290,8 +291,8 @@ example,
(define-module (my mod)
#:autoload (srfi srfi-1) (partition delete-duplicates))
...
(if something
(set! foo (delete-duplicates ...)))
(when something
(set! foo (delete-duplicates ...)))
@end example
When a module is autoloaded, all its bindings become available.
@ -922,7 +923,7 @@ However, as Scheme godparent Mathias Felleisen wrote in ``On the
Expressive Power of Programming Languages'', a more expressive language
is necessarily harder to reason about. There are transformations that
Guile's compiler would like to make which can't be done if every
top-level binding is subject to mutation at any time.
top-level definition is subject to mutation at any time.
Consider this module:
@ -946,6 +947,9 @@ text. However, in the general case it could be that a programmer could
reach into the @code{(boxes)} module at any time and change the value of
@code{box-ref}.
@cindex declarative
@cindex modules, declarative
@cindex definitions, declarative
To allow Guile to reason about the values of top-levels from a module, a
module can be marked as @dfn{declarative}. This flag applies only to
the subset of top-level definitions that are themselves declarative:
@ -965,7 +969,7 @@ By default, modules are compiled declaratively if the
@code{user-modules-declarative?} parameter is true when the
module is compiled.
@deffn {Scheme Parameter} user-modules-declarative-by-default?
@deffn {Scheme Parameter} user-modules-declarative?
A boolean indicating whether definitions in modules created by
@code{define-module} or implicitly as part of a compilation unit without
an explicit module can be treated as declarative.
@ -974,6 +978,76 @@ an explicit module can be treated as declarative.
Because it's usually what you want, the default value of
@code{user-modules-declarative?} is @code{#t}.
@subsubheading Should I Mark My Module As Declarative?
In the vast majority of use cases, declarative modules are what you
want. However, there are exceptions.
Consider the @code{(boxes)} module above. Let's say you want to be able
to go in and change the definition of @code{box-set!} at run-time:
@example
scheme@@(guile-user)> (use-modules (boxes))
scheme@@(guile-user)> ,module boxes
scheme@@(boxes)> (define (box-set! x y) (set-car! x (pk y)))
@end example
However, considering that @code{(boxes)} is a declarative module, it
could be that @code{box-swap!} inlined the call to @code{box-set!} -- so
it may be that you are surprised if you call @code{(box-swap! x y)} and
you don't see the new definition being used. (Note, however, that Guile
has no guarantees about what definitions its compiler will or will not
inline.)
If you want to allow the definition of @code{box-set!} to be changed and
to have all of its uses updated, then probably the best option is to
edit the module and reload the whole thing:
@example
scheme@@(guile-user)> ,reload (boxes)
@end example
The advantage of the reloading approach is that you maintain the
optimizations that declarative modules enable, while also being able to
live-update the code. If the module keeps precious program state, those
definitions can be marked as @code{define-once} to prevent reloads from
overwriting them. @xref{Top Level}, for more on @code{define-once}.
Incidentally, @code{define-once} also prevents declarative-definition
optimizations, so if there's a limited subset of redefinable bindings,
@code{define-once} could be an interesting tool to mark those
definitions as works-in-progress for interactive program development.
To users, whether a module is declarative or not is mostly immaterial:
besides normal use via @code{use-modules}, users can reference and
redefine public or private bindings programmatically or interactively.
The only difference is that changing a declarative definition may not
change all of its uses. If this use-case is important to you, and if
reloading whole modules is insufficient, then you can mark all
definitions in a module as non-declarative by adding
@code{#:declarative? #f} to the module definition.
The default of whether modules are declarative or not can be controlled
via the @code{(user-modules-declarative?)} parameter mentioned above,
but care should be taken to set this parameter when the modules are
compiled, e.g. via @code{(eval-when (expand) (user-modules-declarative?
#f))}. @xref{Eval When}.
Alternately you can prevent declarative-definition optimizations by
compiling at the @code{-O1} optimization level instead of the default
@code{-O2}, or via explicitly passing @code{-Ono-letrectify} to the
@code{guild compile} invocation. @xref{Compilation}, for more on
compiler options.
@cindex inlining
One final note. Currently, definitions from declarative modules can
only be inlined within the module they are defined in, and within a
compilation unit. This may change in the future to allow Guile to
inline imported declarative definitions as well (cross-module inlining).
To Guile, whether a definition is inlinable or not is a property of the
definition, not its use. We hope to improve compiler tooling in the
future to allow the user to identify definitions that are out of date
when a declarative binding is redefined.
@node Accessing Modules from C
@subsection Accessing Modules from C

View file

@ -59,7 +59,12 @@
;; Avoid resolve-primitives until -O2, when CPS optimizations kick in.
;; Otherwise, inlining the primcalls during Tree-IL->CPS compilation
;; will result in a lot of code that will never get optimized nicely.
;; Similarly letrectification is great for generated code quality, but
;; as it gives the compiler more to work with, it increases compile
;; time enough that we reserve it for -O2. Also, this makes -O1 avoid
;; assumptions about top-level values, in the same way that avoiding
;; resolve-primitives does.
'((#:resolve-primitives? 2)
(#:expand-primitives? 1)
(#:letrectify? 1)
(#:letrectify? 2)
(#:partial-eval? 1)))