llvm-hs-9.0.1: General purpose LLVM bindings
Copyright(c) Moritz Kiefer 2018
Stephen Diehl 2018
Benjamin Scarlett 2016
Maintainermoritz.kiefer@purelyfunctional.org
Safe HaskellNone
LanguageHaskell2010

LLVM

Description

 
Synopsis

Documentation

Overview of the llvm-hs library ecosystem

The main two libraries in the llvm-hs ecosystem are llvm-hs-pure and llvm-hs.

  • llvm-hs-pure defines a pure Haskell representation of the LLVM AST. It has no dependency on the LLVM C/C++ libraries so even if you have trouble installing those or want to avoid that dependency, you should be able to use it. The documentation in LLVM.AST describes the different options for constructing the AST.
  • llvm-hs then builds upon llvm-hs-pure and provides the actual FFI bindings to LLVM’s C++ libraries. Most importantly this includes bidirectional conversions from the Haskell representation of an LLVM module to the C++ representation and the other way around.

Once you have constructed the C++ representation, there are two main options:

  1. Generate object code as described in LLVM
  2. or JIT compile the module as described in LLVM.

In addition to llvm-hs and llvm-hs-pure, there are a couple of other libraries that you be interested in:

  • llvm-hs-pretty a pure Haskell prettyprinter for the AST in llvm-hs-pure. This is useful if you just want to render your AST to LLVM’s textual IR format either for debugging purposes (llc will usually give pretty good error messages for invalid IR) or because you prefer to call the LLVM CLI tools over the linking against the LLVM libraries.
  • llvm-hs-typed contains a strongly-typed wrapper for the AST in llvm-hs-pure which makes it harder to accidentally construct invalid LLVM IR.
  • llvm-hs-quote contains a Haskell quasiquoter that can be used for splicing larger chunks of existing LLVM IR into your Haskell code.

Finally, there is a translation of LLVM’s official Kaleidoscope tutorial to llvm-hs and you can find small, self-contained examples covering various parts of the API in the llvm-hs-examples repository.

Constructing the C++ representation of an LLVM module

Interacting with the LLVM libraries requires that you first construct the C++ representation of an LLVM Module.

The most common way of doing that is to first construct the Haskell representation of an LLVM module using llvm-hs-pure. You can then use withModuleFromAST to convert the Haskell AST to the C++ representation.

Alternatively, you can also construct a module from LLVM’s textual IR or the binary bitcode format using withModuleFromLLVMAssembly and withModuleFromBitcode.

Generating object code

Once you have constructed the C++ representation of an LLVM Module, you can generate an object file using moduleObject which will give you a ByteString or write it to a file using writeObjectToFile. To construct the TargetMachine for these functions you can use withHostTargetMachine if you want to generate object code for the machine you are currently running on or use withTargetMachine and customize the target machine based on your needs.

JIT compilation

In addition to generating object code, you can also JIT-compile LLVM modules and call functions in the resulting Module from Haskell.

LLVM has several JIT compilers but ORC JIT is the one that is actively being developed and the one best supported by llvm-hs.

To use ORC JIT you first have to create a CompileLayer. You can then use withModule to add an LLVM module to the compile layer and finally use findSymbol to get the address of a symbol in the module. In most cases, you want to lookup the address of a function so you have to first convert the WordPtr to a FunPtr using wordPtrToPtr and castPtrToFunPtr. Then you can use a foreign dynamic import to construct a Haskell function which will call the function located at the FunPtr.