See also the section on Compiler Plugins in GHC's User's Guide.
New Plugins work
Plugins are a new feature in GHC 7.2.1 that allows users to write compiler passes (for things like optimizations) over GHC's internal intermediate language, Core.
GHC understands the -fplugin
and -fplugin-arg
options. You essentially install plugins for GHC by cabal install
ing them, as they expose a module implementing an interface, and then calling GHC in the form of:
$ ghc -fplugin=Some.Plugin.Module -fplugin-opt=Some.Plugin.Module:no-fizzbuzz a.hs
Warning: this can fail with non obvious error messages if in the same directory as the Some.Plugin.Module source; seems GHC tries to use the source instead of the installed package.
Some.Plugin.Module
should export a symbol named 'plugin' - see the following repositories for examples that do Common Subexpression Elimination, turn Haskell into a strict language, and implement a loop unroller:
https://github.com/thoughtpolice/cse-ghc-plugin
https://github.com/thoughtpolice/strict-ghc-plugin
https://github.com/thoughtpolice/unroll-ghc-plugin
Basic overview of the plugins API for Core
Modules can be loaded by GHC as compiler plugins by exposing a declaration called 'plugin' of type Plugin, which is an ADT containing a function that installs a pass into the Core pipeline.
module Some.Plugin.Module (plugin) where
import GhcPlugins
plugin :: Plugin
plugin = defaultPlugin {
installCoreToDos = install
}
-- type CommandLineOption = String
install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
install _options passes = do
...
We can think of CoreToDo
as being a type synonym for (Core -> Core)
- that is, the install
function just inserts its own CoreToDo
into the list of compiler passes. For example, the CSE pass actually couples a simplification pass, followed by CSE itself into the front of the compilation pipeline:
module CSE.Plugin where
...
install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
install _ xs = return $ CoreDoPasses [defaultGentleSimplToDo, cse] : xs
where cse = CoreDoPluginPass "Common Subexpression Elimination" (bindsOnlyPass cseProgram)
cseProgram :: [CoreBind] -> CoreM [CoreBind]
cseProgram binds = do
...
More specifically, a CoreToDo
describes some sort of particular pass over a Core program that can be invoked as many times as you like. For reference, defaultGentlSimplToDo
is constructed using CoreDoSimplify
. In this case, cse_pass
is constructed using CoreDoPluginsPass
, which takes a name and a function of type ModGuts -> CoreM ModGuts
- ModGuts
is a type that represents the 1 module GHC is compiling at any time. You normally want to manipulate the field mg_binds
of a ModGuts
, which contains all the top-level bindings for the module.
bindsOnlyPass
is a function that merely lifts a function over binders to a function over ModGuts. It's the simple case where nothing else from the ModGuts
is needed.
More details on plugins for end-users can be found in the users guide.
The Future
Plugins for Cmm
Aside from manipulating the core language, we would also like to manipulate the C-- representation GHC generates for modules too.
TODO fixme
Rough API possibilities
TODO fixme