LLVM bindings for Haskell

I’ve spent a bit of time over the past few days putting together some LLVM bindings for Haskell, based on Gordon Henriksen’s C bindings.

(If you don’t know what LLVM is, it’s a wonderful toybox of compiler components, from a complete toolchain supporting multiple architectures through a set of well-defined APIs and intermediate representation file formats that are designed for building interesting software.)

The C bindings are almost untyped, but the Haskell bindings re-add type safety to prevent runtime crashes and general badness.

Currently, almost the entire code generation system is implemented, with most LLVM data types supported (notably absent are structs). Also plugged in is JIT support, so you can generate code at runtime from Haskell and run it immediately. I’ve attached an example.

Please join in the hacking fun! Here’s the darcs repository:

darcs get http://darcs.serpentine.com/llvm

If you want a source tarball, fetch it from here for now. Hackage can’t yet host code that uses GHC 6.8.2′s language extension names.

There’s very light documentation at present, but it ought to be enough to get you going.

Here’s a quick example of some code “in the wild”:

buildFib :: T.Module -> IO (V.Function T.Int32 T.Int32)
buildFib m = do
  let one = C.const (1::Int32)
      two = C.const (2::Int32)
  -- the compiler infers the type for the function from our signature
  (fib, entry) <- U.defineFunction m "fib" (T.function undefined undefined)

  -- a builder is an instruction emitter
  bld <- B.createBuilder
  exit <- Core.appendBasicBlock fib "return"
  recurse <- Core.appendBasicBlock fib "recurse"
  let arg = V.params fib

  -- make the builder emit instructions in the "entry" basic block
  B.positionAtEnd bld entry
  -- if our argument is less than two, exit, else recurse
  test <- B.icmp bld "" I.IntSLE arg two
  B.condBr bld test exit recurse

  -- this is the exit basic block
  B.positionAtEnd bld exit
  B.ret bld one

  -- here's the recursion case
  B.positionAtEnd bld recurse
  x1 <- B.sub bld "" arg one
  fibx1 <- B.call bld "" fib x1

  x2 <- B.sub bld "" arg two
  fibx2 <- B.call bld "" fib x2

  B.add bld "" fibx1 fibx2 >>= B.ret bld

  -- hand the function definition back to our caller
  return fib

This emits a function definition that computes the Fibonacci series in LLVM assembly language. Run it under a JIT:

main :: IO ()
main = do
  args <- getArgs
  let args' = if null args then ["10"] else args

  m <- Core.createModule "fib"
  fib <- buildFib m
  -- print the function definition to the screen
  V.dumpValue fib

  -- create a JIT
  prov <- Core.createModuleProviderForExistingModule m
  ee <- EE.createExecutionEngine prov
  
  -- evaluate the JITted fib function over every command line argument
  forM_ args' $ \num -> do
    putStr $ "fib " ++ num ++ " = "
    parm <- EE.createGeneric (read num :: Int)
    gv <- EE.runFunction ee fib [parm]
    print (EE.fromGeneric gv :: Int)

Running this on the command line gives the following output:

$ ./Fibonacci 

define i32 @fib(i32) {
entry:
        icmp sle i32 %0, 2              ; <i1>:1 [#uses=1]
        br i1 %1, label %return, label %recurse

return:         ; preds = %entry
        ret i32 1

recurse:                ; preds = %entry
        sub i32 %0, 1           ; <i32>:2 [#uses=1]
        call i32 @fib( i32 %2 )         ; :3 [#uses=1]
        sub i32 %0, 2           ; <i32>:4 [#uses=1]
        call i32 @fib( i32 %4 )         ; <i32>:5 [#uses=1]
        add i32 %3, %5          ; <i32>:6 [#uses=1]
        ret i32 %6
}

fib 10 = 55
Posted in haskell, open source
One comment on “LLVM bindings for Haskell
  1. Dennis says:

    Thanks for the module, Bryan! But it looks like you forgot some import statements.

    Fibonacci.hs:2:13:
    Not in scope: type constructor or class `T.Module’

    Fibonacci.hs:2:29:
    Not in scope: type constructor or class `V.Function’

    Fibonacci.hs:2:40:
    Not in scope: type constructor or class `T.Int32′

    Fibonacci.hs:2:48:
    Not in scope: type constructor or class `T.Int32′

    Fibonacci.hs:4:13: Not in scope: `C.const’

4 Pings/Trackbacks for "LLVM bindings for Haskell"
  1. [...] a comment » Brian O’Sullivan first announced the Haskell LLVM bindings on his [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>