The -O* options specify convenient
“packages” of optimisation flags; the
-f* options described later on specify
individual optimisations to be turned on/off;
the -m* options specify
machine-specific optimisations to be turned
on/off.
There are many options that affect
the quality of code produced by GHC. Most people only have a
general goal, something like “Compile quickly” or
“Make my program run like greased lightning.” The
following “packages” of optimisations (or lack
thereof) should suffice.
Once you choose a -O*
“package,” stick with it—don't chop and
change. Modules' interfaces will change
with a shift to a new -O* option, and you may
have to recompile a large chunk of all importing modules before
your program can again be run safely (see Section 4.9.5).
No -O*-type option specified:
This is taken to mean: “Please compile
quickly; I'm not over-bothered about compiled-code
quality.” So, for example: ghc -c
Foo.hs
-O0:
Means “turn off all optimisation”,
reverting to the same settings as if no
-O options had been specified. Saying
-O0 can be useful if
eg. make has inserted a
-O on the command line already.
-O or -O1:
Means: “Generate good-quality code without
taking too long about it.” Thus, for example:
ghc -c -O Main.lhs
-O2:
Means: “Apply every non-dangerous
optimisation, even if it means significantly longer
compile times.”
The avoided “dangerous” optimisations
are those that can make runtime or space
worse if you're unlucky. They are
normally turned on or off individually.
At the moment, -O2 is
unlikely to produce better code than
-O.
-Ofile <file>:
(NOTE: not supported yet in GHC 5.x. Please ask if
you're interested in this.)
For those who need absolute
control over exactly what options are
used (e.g., compiler writers, sometimes :-), a list of
options can be put in a file and then slurped in with
-Ofile.
In that file, comments are of the
#-to-end-of-line variety; blank
lines and most whitespace is ignored.
Please ask if you are baffled and would like an
example of -Ofile!
We don't use a -O* flag for day-to-day
work. We use -O to get respectable speed;
e.g., when we want to measure something. When we want to go for
broke, we tend to use -O -fvia-C (and we go for
lots of coffee breaks).
The easiest way to see what -O (etc.)
“really mean” is to run with -v,
then stand back in amazement.
These flags turn on and off individual optimisations.
They are normally set via the -O options
described above, and as such, you shouldn't need to set any of
them explicitly (indeed, doing so could lead to unexpected
results). However, there are one or two that may be of
interest:
-fexcess-precision:
When this option is given, intermediate floating
point values can have a greater
precision/range than the final type. Generally this is a
good thing, but some programs may rely on the exact
precision/range of
Float/Double values
and should not use this option for their compilation.
-fignore-asserts:
Causes GHC to ignore uses of the function
Exception.assert in source code (in
other words, rewriting Exception.assert p
e to e (see Section 7.4). This flag is turned on by
-O.
-fno-strictness
Turns off the strictness analyser; sometimes it eats
too many cycles.
-fno-cpr-analyse
Turns off the CPR (constructed product result)
analysis; it is somewhat experimental.
-funbox-strict-fields:
This option causes all constructor fields which are
marked strict (i.e. “!”) to be unboxed or
unpacked if possible. For example:
data T = T !Float !Float
will create a constructor T
containing two unboxed floats if the
-funbox-strict-fields flag is given.
This may not always be an optimisation: if the
T constructor is scrutinised and the
floats passed to a non-strict function for example, they
will have to be reboxed (this is done automatically by the
compiler).
This option should only be used in conjunction with
-O, in order to expose unfoldings to the
compiler so the reboxing can be removed as often as
possible. For example:
f :: T -> Float
f (T f1 f2) = f1 + f2
The compiler will avoid reboxing
f1 and f2 by
inlining + on floats, but only when
-O is on.
Any single-constructor data is eligible for
unpacking; for example
data T = T !(Int,Int)
will store the two Ints directly
in the T constructor, by flattening
the pair. Multi-level unpacking is also supported:
data T = T !S
data S = S !Int !Int
will store two unboxed Int#s
directly in the T constructor.
-funfolding-update-in-place<n>
Switches on an experimental "optimisation".
Switching it on makes the compiler a little keener to
inline a function that returns a constructor, if the
context is that of a thunk.
x = plusInt a b
If we inlined plusInt we might get an opportunity to use
update-in-place for the thunk 'x'.
-funfolding-creation-threshold<n>:
(Default: 45) Governs the maximum size that GHC will
allow a function unfolding to be. (An unfolding has a
“size” that reflects the cost in terms of
“code bloat” of expanding that unfolding at
at a call site. A bigger function would be assigned a
bigger cost.)
Consequences: (a) nothing larger than this will be
inlined (unless it has an INLINE pragma); (b) nothing
larger than this will be spewed into an interface
file.
Increasing this figure is more likely to result in longer
compile times than faster code. The next option is more
useful:
-funfolding-use-threshold<n>:
(Default: 8) This is the magic cut-off figure for
unfolding: below this size, a function definition will be
unfolded at the call-site, any bigger and it won't. The
size computed for a function depends on two things: the
actual size of the expression minus any discounts that
apply (see -funfolding-con-discount).