7. Hacking on the Futhark Compiler¶
The Futhark compiler is a significant body of code with a not entirely straightforward design. The main reference is the documentation of the compiler internals that is automatically generated by Haddock. If you feel that it is incomplete, or lacks an explanation, then feel free to report it is an an issue on the Github page. Documentation bugs are bugs too.
The Futhark compiler is built using Stack. It’s a good idea to familiarise yourself with how it works. As a starting point, here are a few hints:
To test with different GHC versions, point the
STACK_YAMLenvironment variable at another file. For example, to build using the Stack LTS 1.15 snapshot (GHC 7.8), we would run:$ STACK_YAML=stack-lts-1.15.yaml stack build
When testing, pass
stackto disable the GHC optimiser. This speeds up builds considerably (although it still takes a while). The resulting Futhark compiler will run slower, but it is not something you will notice for small test programs.
When debugging, pass
stack. This will build the Futhark compiler with debugging information (not just profiling). In particular, hard crashes will print a stack trace. You can also get actual profiling information by passing
+RTS -pprof-all -RTSto the Futhark compiler. This asks the Haskell runtime to print profiling information to a file. For more information, see the Profiling chapter in the GHC User Guide.
You may with to set the environment variable
FUTHARK_COMPILER_DEBUGGING=1. Currently this only has the effect of making the frontend print internal names, but it may control more things in the future.
When hacking on the compiler frontend, you might want to change the definition of
emptyBasis. This drastically cuts down on the compilation time of the Futhark compiler itself, although Futhark programs will take a little longer to type-check (roughly 200ms).
7.1. Debugging Internal Type Errors¶
The Futhark compiler uses a typed core language, and the type checker
is run after every pass. If a given pass produces a program with
inconsistent typing, the compiler will report an error and abort.
While not every compiler bug will manifest itself as a core language
type error (unfortunately), many will. To write the erroneous core
program to a file in case of type error, pass
-v filename to the
compiler. This will also enable verbose output, so you can tell which
pass fails. The
-v option is also useful when the compiler itself
crashes, as you can at least tell where in the pipeline it got to.
7.2. Checking Generated Code¶
Hacking on the compiler will often involve inspecting the quality of the generated code. The recommended way to do this is to use futhark-c or futhark-opencl to compile a Futhark program to an executable. These backends insert various forms of instrumentation that can be enabled by passing run-time options to the generated executable.
- As a first resort, use
-toption to use the built-in runtime measurements. A nice trick is to pass
-t /dev/stderr, while redirecting standard output to
/dev/null. This will print the runtime on the screen, but not the execution result.
- Optionally use
-rto ask for several runs, e.g.
-r 10. If combined with
-t, this will cause several runtimes to be printed (one per line). The futhark-bench tool itself uses
-rto perform its measurements.
-Dto have the program print information on allocation and deallocation of memory.
- (futhark-opencl only) Use the
-Doption to enable synchronous execution.
clFinish()will be called after most OpenCL operations, and a running log of kernel invocations will be printed. At the end of execution, the program prints a table summarising all kernels and their total runtime and average runtime.
7.3. Using the
For debugging specific compiler passes, the
futhark dev subcommand
allows you to tailor your own compilation pipeline using command line
options. It is also useful for seeing what the AST looks like after