ASTs and Modules
We’ll refer to a Module as holding the internal representation of the LLVM IR. Modules can be generated from the Haskell LLVM AST or from strings containing bitcode.
Both data types have the same name ( Module ), so as convention we will qualify the imports of the libraries to distinguish between the two.
AST.Module
: Haskell AST ModuleModule
: Internal LLVM Module
llvm-hs provides two important functions for converting between them. withModuleFromAST
has type ExceptT
since it may fail if given a malformed expression, it is important to handle both cases of the resulting Either value.
withModuleFromAST :: Context -> AST.Module -> (Module -> IO a) -> ExceptT String IO a
moduleAST :: Module -> IO AST.Module
We can also generate the assembly code for our given module by passing a specification of the CPU and platform information we wish to target, called the TargetMachine
.
moduleTargetAssembly :: TargetMachine -> Module -> ExceptT String IO String
Recall the so called “Bracket” pattern in Haskell for managing IO resources. llvm-hs makes heavy use this pattern to manage the life-cycle of certain LLVM resources. It is very important to remember not to pass or attempt to use resources outside of the bracket as this will lead to undefined behavior and/or segfaults.
bracket :: IO a -- computation to run first ("acquire resource")
-> (a -> IO b) -- computation to run last ("release resource")
-> (a -> IO c) -- computation to run in-between
-> IO c
In addition to this we’ll often be dealing with operations which can fail in an EitherT
monad if given bad code. We’ll often want to lift this error up the monad transformer stack with the pattern:
liftExcept :: ExceptT String IO a -> IO a
liftExcept = runExceptT >=> either fail return
To start we’ll create a runJIT
function which will start with a stack of brackets. We’ll then simply generate the IR and print it out to the screen.
runJIT :: AST.Module -> IO (Either String ())
runJIT mod = do
withContext $ \context ->
runErrorT $ withModuleFromAST context mod $ \m ->
s <- moduleLLVMAssembly m
putStrLn s