| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
LLVM.IRBuilder
Description
This module provides a high-level monadic DSL for LLVM IR modules,
functions, blocks, and instructions. The IRBuilder monad encapsulates the
state of IR construction and provides error handling for common failure modes.
Example usage:
module <- compileModule "my_module" $ do
define i32 "main" [] LExternal [] $ do
beginBlock "entry"
result <- add i32 (OConstant (CInt 32 1)) (OConstant (CInt 32 2))
ret result
Synopsis
- newtype IRBuilderT (m :: Type -> Type) a = IRBuilderT {
- runIRBuilderT :: StateT IRBuilderEnv (ExceptT IRBuilderError m) a
- type IRBuilder = IRBuilderT Identity
- class Monad m => MonadIRBuilder (m :: Type -> Type) where
- getIRBuilderEnv :: m IRBuilderEnv
- putIRBuilderEnv :: IRBuilderEnv -> m ()
- throwIRBuilderError :: IRBuilderError -> m a
- modifyIRBuilderEnv :: (IRBuilderEnv -> IRBuilderEnv) -> m ()
- getsIRBuilderEnv :: (IRBuilderEnv -> a) -> m a
- runIRBuilder :: IRBuilder a -> StateT IRBuilderEnv (ExceptT IRBuilderError Identity) a
- data IRBuilderEnv = IRBuilderEnv {}
- emptyIRBuilderEnv :: IRBuilderEnv
- lift :: (MonadTrans t, Monad m) => m a -> t m a
- compileModule :: IRName -> IRBuilder a -> Text
- compileModuleWith :: IRName -> IRBuilder a -> Either IRBuilderError Text
- buildModuleWith :: IRName -> IRBuilder a -> Either IRBuilderError (IRModule, a)
- buildModule :: IRName -> IRBuilder a -> IRModule
- compileModuleM :: MonadIRBuilder m => IRName -> m a -> m Text
- compileModuleWithM :: MonadIRBuilder m => IRName -> m a -> m (Text, a)
- buildModuleWithM :: MonadIRBuilder m => IRName -> m a -> m (IRModule, a)
- buildModuleM :: MonadIRBuilder m => IRName -> m a -> m IRModule
- define :: MonadIRBuilder m => IRType -> IRName -> [(IRType, IRName)] -> IRLinkage -> [IRAttribute] -> m a -> m a
- beginFunction :: MonadIRBuilder m => FunctionBuilder -> m ()
- endFunction :: MonadIRBuilder m => m ()
- beginBlock :: MonadIRBuilder m => IRName -> m ()
- block :: MonadIRBuilder m => IRName -> m IRName
- finalizeCurrentBlock :: MonadIRBuilder m => m ()
- emitInstruction :: MonadIRBuilder m => IRInstruction (Maybe Text) -> m ()
- emitAnnotation :: MonadIRBuilder m => IRAnnotation -> m ()
- emitTerminator :: MonadIRBuilder m => IRTerminator -> m ()
- emitGlobal :: MonadIRBuilder m => IRGlobal -> m ()
- emitTypeDecl :: MonadIRBuilder m => IRName -> IRType -> m ()
- declare :: MonadIRBuilder m => IRName -> IRType -> [IRType] -> m ()
- declareVarArg :: MonadIRBuilder m => IRName -> IRType -> [IRType] -> m ()
- setTerminator :: MonadIRBuilder m => IRTerminator -> m ()
- (<##>) :: MonadIRBuilder m => m a -> Text -> m a
- getCurrentBlockM :: MonadIRBuilder m => m BlockBuilder
- getCurrentFunctionM :: MonadIRBuilder m => m FunctionBuilder
- liftEither :: MonadIRBuilder m => Either IRBuilderError a -> m a
- data IRAtomicOrdering
- data IRAtomicOp
Core types and compilation
newtype IRBuilderT (m :: Type -> Type) a Source #
The IRBuilderT monad transformer for constructing LLVM IR.
This transformer allows IR construction operations to be embedded in any monad. It combines:
StateTfor maintaining the builder environment (current function, block, etc.)ExceptTfor error handling with typedIRBuilderErrorexceptions- A parameterized base monad
m
Use runIRBuilderT to extract the inner transformer stack for execution.
The monad supports MonadFix when the base monad does, enabling forward references
with mdo notation in recursive block structures like loops with phi nodes.
Constructors
| IRBuilderT | |
Fields
| |
Instances
type IRBuilder = IRBuilderT Identity Source #
Specialized IRBuilderT using Identity as the base monad.
This is the original non-transformer version, maintained for backward compatibility. Most existing code uses this type.
class Monad m => MonadIRBuilder (m :: Type -> Type) where Source #
MTL-style typeclass for monads that support IR building operations.
This class provides primitives for accessing and modifying the builder environment and throwing builder-specific errors. It is designed to be composable with other monad transformers via lift-through instances.
Minimal complete definition: getIRBuilderEnv, putIRBuilderEnv, throwIRBuilderError
Minimal complete definition
Methods
getIRBuilderEnv :: m IRBuilderEnv Source #
Retrieve the current builder environment.
putIRBuilderEnv :: IRBuilderEnv -> m () Source #
Replace the current builder environment.
throwIRBuilderError :: IRBuilderError -> m a Source #
Throw a builder error, short-circuiting the computation.
modifyIRBuilderEnv :: (IRBuilderEnv -> IRBuilderEnv) -> m () Source #
Modify the builder environment using a function.
Default implementation in terms of getIRBuilderEnv and putIRBuilderEnv.
getsIRBuilderEnv :: (IRBuilderEnv -> a) -> m a Source #
Retrieve a projection of the builder environment.
Default implementation in terms of getIRBuilderEnv.
Instances
runIRBuilder :: IRBuilder a -> StateT IRBuilderEnv (ExceptT IRBuilderError Identity) a Source #
Extract the transformer stack from an IRBuilder computation.
For backward compatibility with code that uses runIRBuilder directly.
data IRBuilderEnv Source #
Constructors
| IRBuilderEnv | |
Instances
| Show IRBuilderEnv Source # | |
Defined in LLVM.IRBuilder.Environment Methods showsPrec :: Int -> IRBuilderEnv -> ShowS # show :: IRBuilderEnv -> String # showList :: [IRBuilderEnv] -> ShowS # | |
| Eq IRBuilderEnv Source # | |
Defined in LLVM.IRBuilder.Environment | |
| Ord IRBuilderEnv Source # | |
Defined in LLVM.IRBuilder.Environment Methods compare :: IRBuilderEnv -> IRBuilderEnv -> Ordering # (<) :: IRBuilderEnv -> IRBuilderEnv -> Bool # (<=) :: IRBuilderEnv -> IRBuilderEnv -> Bool # (>) :: IRBuilderEnv -> IRBuilderEnv -> Bool # (>=) :: IRBuilderEnv -> IRBuilderEnv -> Bool # max :: IRBuilderEnv -> IRBuilderEnv -> IRBuilderEnv # min :: IRBuilderEnv -> IRBuilderEnv -> IRBuilderEnv # | |
| Monad m => MonadState IRBuilderEnv (IRBuilderT m) Source # | |
Defined in LLVM.IRBuilder Methods get :: IRBuilderT m IRBuilderEnv # put :: IRBuilderEnv -> IRBuilderT m () # state :: (IRBuilderEnv -> (a, IRBuilderEnv)) -> IRBuilderT m a # | |
lift :: (MonadTrans t, Monad m) => m a -> t m a #
Lift a computation from the argument monad to the constructed monad.
compileModule :: IRName -> IRBuilder a -> Text Source #
Compile an LLVM IR module to text, terminating on error.
This is the primary entry point for IR generation. It executes the builder monad, finalizes all pending blocks and functions, and renders the complete module to LLVM assembly text format.
On error, this function will call error with a descriptive message.
For explicit error handling, use compileModuleWith.
Example:
let code = compileModule "my_module" $ do
define i32 "main" [] LExternal [] $ do
beginBlock "entry"
x <- add i32 (OConstant (CInt 32 1)) (OConstant (CInt 32 2))
ret x
putStrLn code
Args:
- First argument: module name
- Second argument: builder computation
Returns: LLVM assembly as Text
Throws (via error): Any IRBuilderError encountered during building
compileModuleWith :: IRName -> IRBuilder a -> Either IRBuilderError Text Source #
Compile an LLVM IR module to text with explicit error handling.
This is the result-returning variant of compileModule. It executes the builder,
finalizes all blocks and functions, and renders the module to LLVM assembly text.
For automatic error handling (terminates on error), use compileModule.
Args:
- First argument: module name
- Second argument: builder computation
Returns: where:Either IRBuilderError Text
- Left: construction or rendering error
- Right: LLVM assembly text
Errors: Returns Left on any IRBuilderError during building
buildModuleWith :: IRName -> IRBuilder a -> Either IRBuilderError (IRModule, a) Source #
Build an LLVM IR module with explicit error handling.
This is the result-returning variant of buildModule. It executes the builder
computation and returns the result as an Either, allowing callers to handle
errors explicitly rather than via error.
Args:
- First argument: module name
- Second argument: builder computation
Returns: where:Either IRBuilderError (IRModule, a)
- Left: construction error
- Right: tuple of (module, builder result)
Errors: Returns Left on any IRBuilderError during construction
buildModule :: IRName -> IRBuilder a -> IRModule Source #
Build an LLVM IR module, terminating on error.
This is the primary entry point for IR module construction. It executes the
builder monad and returns the complete IR module. If any error occurs during
construction, the program terminates with error.
For explicit error handling, use buildModuleWith.
Args:
- First argument: module name
- Second argument: builder computation
Returns: The constructed IRModule
Throws (via error): Any IRBuilderError encountered during construction
compileModuleM :: MonadIRBuilder m => IRName -> m a -> m Text Source #
Compile an LLVM IR module to text in any MonadIRBuilder context.
This is the generalized version of compileModule that works with any monad
implementing MonadIRBuilder. It's a convenience wrapper around compileModuleWithM
that discards the computation result.
Args:
- First argument: module name
- Second argument: builder computation in any
MonadIRBuilder
Returns: LLVM assembly as Text
Throws: Propagates any IRBuilderError via throwIRBuilderError
Example:
text <- compileModuleM "my_module" $ do
define i32 "main" [] LExternal [] $ do
beginBlock "entry"
customMonadOperation
ret (OConstant (CInt 32 0))
compileModuleWithM :: MonadIRBuilder m => IRName -> m a -> m (Text, a) Source #
Compile an LLVM IR module to text in any MonadIRBuilder context, with result.
This is the generalized version of compileModuleWith that works with any monad
implementing MonadIRBuilder. It builds the module and renders it to LLVM assembly,
returning both the text and the computation result.
Args:
- First argument: module name
- Second argument: builder computation in any
MonadIRBuilder
Returns: Tuple of (LLVM assembly Text, computation result)
Throws: Propagates any IRBuilderError via throwIRBuilderError
buildModuleWithM :: MonadIRBuilder m => IRName -> m a -> m (IRModule, a) Source #
Build an LLVM IR module in any MonadIRBuilder context, with result.
This is the generalized version of buildModuleWith that works with any monad
implementing MonadIRBuilder, such as custom monad stacks built on top of
IRBuilderT. It isolates the module construction in a fresh environment and
returns both the module and the computation result.
The function:
- Saves the current builder environment
- Resets to an empty environment
- Executes the builder computation
- Extracts the final environment to construct the module
- Restores the original environment
- Returns the module and computation result
Args:
- First argument: module name
- Second argument: builder computation in any
MonadIRBuilder
Returns: Tuple of (IRModule, computation result)
Throws: Propagates any IRBuilderError via throwIRBuilderError
Example:
moduleAndResult <- buildModuleWithM "my_module" $ do define i32 "main" [] LExternal [] $ do beginBlock "entry" customMonadOperation -- works with custom MonadIRBuilder instances ret (OConstant (CInt 32 0))
buildModuleM :: MonadIRBuilder m => IRName -> m a -> m IRModule Source #
Build an LLVM IR module in any MonadIRBuilder context.
This is the generalized version of buildModule that works with any monad
implementing MonadIRBuilder. It's a convenience wrapper around buildModuleWithM
that discards the computation result.
Args:
- First argument: module name
- Second argument: builder computation in any
MonadIRBuilder
Returns: The constructed IRModule
Throws: Propagates any IRBuilderError via throwIRBuilderError
Example:
module_ <- buildModuleM "my_module" $ do define i32 "main" [] LExternal [] $ do beginBlock "entry" customMonadOperation ret (OConstant (CInt 32 0))
Function definition
Arguments
| :: MonadIRBuilder m | |
| => IRType | Return type of the function |
| -> IRName | Function name |
| -> [(IRType, IRName)] | Parameter list as |
| -> IRLinkage | |
| -> [IRAttribute] | Function attributes (e.g. |
| -> m a | Body computation that builds the function |
| -> m a |
Define a function with the given signature and body.
This is the primary high-level interface for function definition. It combines
beginFunction and endFunction around a computation.
Args:
retType: the return typename: function nameargs: list of (type, name) parameter pairslinkage: function linkage (e.g.,LExternal,LInternal)attributes: function attributes (e.g.,[APure])body: monadic computation that builds the function body
Returns: the result of the body computation
Example:
define i32 "add" [(i32, "a"), (i32, "b")] LExternal [] $ do beginBlock "entry" result <- add i32 (OLocal i32 "a") (OLocal i32 "b") ret result
Throws: Any error from body computation or finalization
beginFunction :: MonadIRBuilder m => FunctionBuilder -> m () Source #
Begin a new function definition in the current module.
This is a lower-level operation. For a higher-level interface, prefer define.
This function:
- Finalizes the current block (if any)
- Verifies no function is already active
- Activates the given function
Throws: CurrentFunctionActive if a function is already being defined
endFunction :: MonadIRBuilder m => m () Source #
Finalize the current function definition.
This is a lower-level operation. For a higher-level interface, prefer define.
This function:
- Finalizes the current block (if any)
- Constructs the function from current state
- Adds it to the module's function list
- Clears the current function context
Throws: NoCurrentFunction if no function is currently being defined
Block management
beginBlock :: MonadIRBuilder m => IRName -> m () Source #
Begin a new basic block within the current function.
Each block has a label and contains instructions ending with a terminator.
This function:
- Finalizes the previous block (if any)
- Creates a new empty block with the given label
- Makes it the current block
Blocks are accumulated within the function and rendered in order.
Args: block label (e.g., "entry", "loop", "exit")
Throws: BlockMissingTerminator if the previous block lacks a terminator
Example:
beginBlock "entry" beginBlock "loop" beginBlock "exit"
block :: MonadIRBuilder m => IRName -> m IRName Source #
Begin a fresh basic block with a suffixed label.
This is the high-level alternative to beginBlock for use in mdo blocks
where the generated label must be captured and referenced by other
instructions (e.g., br, condbr, phi).
The hint is suffixed with a fresh integer to guarantee uniqueness across nested or repeated uses of the same logical name:
-- "loop" becomes e.g. "loop.1", "body" becomes "body.2" define i64 "fact" [(i64, "n")] LExternal [] $ mdo beginBlock "entry" br loopLabel loopLabel <- block "loop" ... condbr cond bodyLabel exitLabel bodyLabel <- block "body" ... br loopLabel exitLabel <- block "exit" ret result
Returns: the generated block label (e.g., "loop.1")
Throws: BlockMissingTerminator if the previous block lacks a terminator
finalizeCurrentBlock :: MonadIRBuilder m => m () Source #
Finalize the current block and add it to the function's block list.
This is normally called automatically by beginBlock, beginFunction, and
endFunction. It's exported for advanced use cases.
This function:
- Validates the current block has a terminator
- Constructs an
IRBlockfrom current state - Adds it to the current function
- Clears the current block context
Throws: BlockMissingTerminator if the block lacks a terminator
Instruction emission
emitInstruction :: MonadIRBuilder m => IRInstruction (Maybe Text) -> m () Source #
Emit an instruction into the current block.
Instructions are appended to the current block’s instruction list. Each instruction may have an optional inline comment attached via ‘##’.
If no block is currently active, an implicit block labelled "entry" is
created automatically.
This is the low-level primitive that all instruction smart constructors (e.g. ‘add’, ‘mul’, ‘load’) call internally. Prefer those over calling this function directly.
Example (direct use):
emitInstruction IRInstruction
{ instrResult = Just ("x", i32)
, instrOp = IAdd i32 (OLocal i32 "a") (OLocal i32 "b")
, instrMetadata = Nothing
}
emitAnnotation :: MonadIRBuilder m => IRAnnotation -> m () Source #
Emit a comment annotation into the current block.
Annotations are block-level comments useful for documenting logic sections.
Unlike inline comments (via <##>), annotations stand alone as IRBlockItems.
If no block is currently active, an implicit block labelled "entry" is
created automatically.
Example:
emitAnnotation (commentBlock ["Section: input validation", "Check bounds..."])
emitTerminator :: MonadIRBuilder m => IRTerminator -> m () Source #
Emit a terminator instruction for the current block.
Every basic block must end with exactly one terminator (e.g., ret, br, condbr).
If no block is currently active, an implicit block labelled "entry" is created
automatically, mirroring LLVM IR semantics.
This function validates that the block doesn't already have a terminator.
Throws: BlockAlreadyTerminated if the block already has a terminator
emitGlobal :: MonadIRBuilder m => IRGlobal -> m () Source #
Emit a global value (declaration or constant) into the module.
Global values include:
- External declarations (functions, global variables)
- Constant globals
- String constants
Globals are collected in the module and rendered at the top level.
Example:
emitGlobal (declare i32 "printf" [TPtr] ...) emitGlobal (IRGlobalConstant "myString" (IRConstantString "hello") ...)
emitTypeDecl :: MonadIRBuilder m => IRName -> IRType -> m () Source #
Emit a named type declaration into the module.
Renders at the top of the IR output as:
%IRName = type <type>
Duplicate declarations (same name) are silently ignored, so it is safe to call this function multiple times for the same type.
Example:
emitTypeDecl "Node" (TStruct [TInt 32, TPtr, TPtr])
-- renders: %Node = type { i32, ptr, ptr }
declare :: MonadIRBuilder m => IRName -> IRType -> [IRType] -> m () Source #
Emit an external function declaration into the module.
Renders as:
declare <retType> @<name>(<argTypes>)
Duplicate declarations (same function name) are silently ignored, so it is safe to call this freely without tracking what has already been declared.
Example:
declare "printf" TVoid [TPtr] declare "malloc" TPtr [TInt 64]
declareVarArg :: MonadIRBuilder m => IRName -> IRType -> [IRType] -> m () Source #
Emit a variadic external function declaration into the module.
Like declare, but appends ... to the argument list:
declare i32 @printf(ptr, ...)
Duplicate declarations (same function name) are silently ignored.
Example:
declareVarArg "printf" i32 [TPtr] declareVarArg "scanf" i32 [TPtr]
setTerminator :: MonadIRBuilder m => IRTerminator -> m () Source #
Set the terminator instruction for the current block.
Prefer emitTerminator for proper error handling. This is a lower-level
variant used internally.
Utilities
(<##>) :: MonadIRBuilder m => m a -> Text -> m a Source #
Attach an inline comment to the previously emitted instruction.
This operator must immediately follow an instruction-emitting expression. The comment is attached to the instruction's metadata and renders as a line comment in LLVM assembly.
Usage:
result <- add i32 a b <##> "sum of a and b"
This renders as:
%1 = add i32 %a, %b ; sum of a and b
Throws:
NoCurrentBlockif no block is activeNoInstructionForCommentif no instruction was just emittedCommentOnAnnotationif applied to an annotation block instead of an instruction
Error handling
getCurrentBlockM :: MonadIRBuilder m => m BlockBuilder Source #
Retrieve the current active block, throwing NoCurrentBlock if none exists.
This is useful for explicit error handling patterns where you need the current block or want to handle the error case directly instead of relying on other operations to fail.
Throws: NoCurrentBlock if no block is currently active.
getCurrentFunctionM :: MonadIRBuilder m => m FunctionBuilder Source #
Get the current function, throwing NoCurrentFunction if none exists
liftEither :: MonadIRBuilder m => Either IRBuilderError a -> m a Source #
Atomic types
data IRAtomicOrdering Source #
Atomic memory ordering constraints.
Instances
| Show IRAtomicOrdering Source # | |
Defined in LLVM.IRInstruction Methods showsPrec :: Int -> IRAtomicOrdering -> ShowS # show :: IRAtomicOrdering -> String # showList :: [IRAtomicOrdering] -> ShowS # | |
| Eq IRAtomicOrdering Source # | |
Defined in LLVM.IRInstruction Methods (==) :: IRAtomicOrdering -> IRAtomicOrdering -> Bool # (/=) :: IRAtomicOrdering -> IRAtomicOrdering -> Bool # | |
| Ord IRAtomicOrdering Source # | |
Defined in LLVM.IRInstruction Methods compare :: IRAtomicOrdering -> IRAtomicOrdering -> Ordering # (<) :: IRAtomicOrdering -> IRAtomicOrdering -> Bool # (<=) :: IRAtomicOrdering -> IRAtomicOrdering -> Bool # (>) :: IRAtomicOrdering -> IRAtomicOrdering -> Bool # (>=) :: IRAtomicOrdering -> IRAtomicOrdering -> Bool # max :: IRAtomicOrdering -> IRAtomicOrdering -> IRAtomicOrdering # min :: IRAtomicOrdering -> IRAtomicOrdering -> IRAtomicOrdering # | |
data IRAtomicOp Source #
Operations for the IAtomicRMW instruction.
Constructors
| ARMWXchg | |
| ARMWAdd | |
| ARMWSub | |
| ARMWAnd | |
| ARMWNand | |
| ARMWOr | |
| ARMWXor | |
| ARMWMax | |
| ARMWMin | |
| ARMWUMax | |
| ARMWUMin | |
| ARMWFAdd | |
| ARMWFSub | |
| ARMWFMax | |
| ARMWFMin |
Instances
| Show IRAtomicOp Source # | |
Defined in LLVM.IRInstruction Methods showsPrec :: Int -> IRAtomicOp -> ShowS # show :: IRAtomicOp -> String # showList :: [IRAtomicOp] -> ShowS # | |
| Eq IRAtomicOp Source # | |
Defined in LLVM.IRInstruction | |
| Ord IRAtomicOp Source # | |
Defined in LLVM.IRInstruction Methods compare :: IRAtomicOp -> IRAtomicOp -> Ordering # (<) :: IRAtomicOp -> IRAtomicOp -> Bool # (<=) :: IRAtomicOp -> IRAtomicOp -> Bool # (>) :: IRAtomicOp -> IRAtomicOp -> Bool # (>=) :: IRAtomicOp -> IRAtomicOp -> Bool # max :: IRAtomicOp -> IRAtomicOp -> IRAtomicOp # min :: IRAtomicOp -> IRAtomicOp -> IRAtomicOp # | |