LLVM Haskell Bindings
Relevant source files
The following files were used as context for generating this wiki page:
- jazz-hs/local-deps/llvm-hs/CHANGELOG.md
- jazz-hs/local-deps/llvm-hs-pure/CHANGELOG.md
- jazz-hs/local-deps/llvm-hs-pretty/ChangeLog.md
- jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/OrcJITC.cpp
- jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/MetadataC.cpp
- jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/InstructionC.cpp
- jazz-hs/local-deps/llvm-hs-pretty/README.md
The LLVM Haskell Bindings provide a comprehensive interface for the Jazz project to interact with the LLVM compiler infrastructure. These bindings are divided into three primary components: llvm-hs (the main FFI bindings to the LLVM C++ API), llvm-hs-pure (a pure Haskell representation of the LLVM AST), and llvm-hs-pretty (a pretty-printer for the AST).
Within the Jazz project architecture, these bindings facilitate the transformation of high-level Jazz code into optimized machine code via LLVM's Just-In-Time (JIT) compilation and code generation capabilities. The bindings support modern LLVM features, including OrcJIT V2, comprehensive Debug Metadata (DWARF), and a monadic IRBuilder for programmatic code generation.
Sources: jazz-hs/local-deps/llvm-hs/CHANGELOG.md, jazz-hs/local-deps/llvm-hs-pretty/README.md, README.md:31-33
Core Architecture and Components
The system is structured as a tiered set of libraries that abstract away the complexities of the LLVM C++ API while providing both high-level Haskell abstractions and low-level FFI access.
| Component | Description |
|---|---|
| llvm-hs | Main library containing FFI bindings, OrcJIT support, and C++ API wrappers. |
| llvm-hs-pure | Pure Haskell implementation of the LLVM AST, allowing AST manipulation without C++ dependencies. |
| llvm-hs-pretty | A library for converting llvm-hs-pure ASTs back into human-readable LLVM IR text. |
| IRBuilder | A monadic API for building LLVM modules and instructions in a style similar to the C++ API. |
Sources: jazz-hs/local-deps/llvm-hs-pure/CHANGELOG.md:120-123, jazz-hs/local-deps/llvm-hs-pretty/README.md:8-12
Data Flow Overview
The following diagram illustrates how Jazz source code moves through the Haskell bindings to produce executable code or LLVM IR.
The flow demonstrates the separation between the pure AST representation used for manipulation and the FFI layer used for actual execution or file generation.
Sources: jazz-hs/local-deps/llvm-hs-pretty/README.md:16-19, jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/OrcJITC.cpp:115-120
OrcJIT V2 Implementation
The project utilizes LLVM's OrcJIT (On-Request Compilation JIT) Version 2 for dynamic execution. This system manages memory, symbol resolution, and compilation layers.
JIT Components and Lifecycle
The JIT execution environment is built around the ExecutionSession, which manages JITDylib instances. Modules are added as ThreadSafeModule objects to ensure thread safety during concurrent compilation.
This diagram shows the initialization and module registration process for the JIT engine.
Sources: jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/OrcJITC.cpp:48-65, jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/OrcJITC.cpp:108-115
Key OrcJIT FFI Functions
LLVM_Hs_createExecutionSession: Initializes the main JIT controller usingSelfExecutorProcessControl.LLVM_Hs_cloneAsThreadSafeModule: Converts a standardLLVMModuleRefinto aThreadSafeModuleby serializing to bitcode and re-parsing into a new context.LLVM_Hs_IRLayer_addModule: Adds a module to a specific compilation layer and JITDylib.LLVM_Hs_ExecutionSession_lookupSymbol: Performs symbol resolution across defined Dylibs.
Sources: jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/OrcJITC.cpp:78-95, jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/OrcJITC.cpp:148-160
Instruction and Metadata Handling
The bindings provide detailed access to LLVM instructions and the Debug Information (DI) metadata system, which is critical for source-level debugging.
Instruction Attributes
Instructions are wrapped to expose properties such as atomicity, fast-math flags, and tail call optimizations.
- Atomic Operations: Supports
AtomicCmpXchg,AtomicRMW,Load, andStorewith specificAtomicOrdering(e.g., Monotonic, Acquire, Release). - Fast Math: Provides flags for floating-point optimizations like
NoNaNs,NoInfs, andAllowReassoc. - Tail Calls: Supports
TailCallKindincludingNone,Tail,MustTail, andNoTail.
Sources: jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/InstructionC.cpp:14-45, jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/InstructionC.cpp:92-100
Metadata Architecture (DWARF)
The metadata system allows Jazz to map generated code back to source locations and types. It handles complex DWARF structures through specialized FFI calls.
The metadata hierarchy allows for nested scope and type definitions within the LLVM IR.
Sources: jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/MetadataC.cpp:140-160, jazz-hs/local-deps/llvm-hs/src/LLVM/Internal/FFI/Metadata.h:10-38
IRBuilder and Monadic Construction
The IRBuilder (found in llvm-hs-pure) provides a high-level API for generating LLVM IR without manually managing pointers.
- MonadModuleBuilder: Tracks global state, such as type definitions and global variables.
- MonadIRBuilder: Provides a context for emitting instructions within a basic block.
- Automatic Resolution: The builder handles
NamedTypeReferenceresolution automatically, especially in complex instructions likegep(GetElementPtr).
Sources: jazz-hs/local-deps/llvm-hs-pure/CHANGELOG.md:28-35, jazz-hs/local-deps/llvm-hs-pure/CHANGELOG.md:113-116
Conclusion
The LLVM Haskell Bindings in the Jazz project provide a robust bridge between Haskell's type safety and LLVM's performance. By leveraging OrcJIT V2 for execution and a comprehensive metadata system for debugging, the project achieves a high-performance functional programming runtime. The separation into pure AST manipulation (llvm-hs-pure) and execution layers (llvm-hs) ensures that the compiler remains modular and testable.
Sources: README.md:20-22, jazz-hs/local-deps/llvm-hs-pretty/README.md:14-16