Visitar URL original
LLVM.IR
ir-builder-0.1.0.0: Monadic DSL for constructing LLVM IR
Safe HaskellNone
LanguageHaskell2010

LLVM.IR

Description

Main entry point for the ir-builder library.

A single import provides the complete public API for constructing, verifying, and rendering LLVM IR:

import LLVM.IR

This module re-exports the builder DSL, all instruction and type constructors, the IR data types, and the verification and rendering functions. Every sub-module remains directly importable for users who need more fine-grained control.

Quick start

Build an IR module containing a simple void function:

import LLVM.IR

example :: Text
example = compileModule "example" $
  define void "hello" [] LExternal [] $ do
    beginBlock "entry"
    retVoid

Produces:

define void @hello() {
entry:
  ret void
}

Run the builder with explicit error handling using compileModuleWith:

case compileModuleWith "example" builder of
  Left err -> putStrLn (displayError err)
  Right ir -> Data.Text.IO.putStr ir

Operand constants

Both LLVM.IRType.Constructors (re-exported here) and LLVM.IROperand.Constructors export names like i32 and ptr — one as a type, one as a constant-operand helper.

To avoid conflicts, LLVM.IROperand.Constructors is not re-exported. Import it qualified whenever you need constant operand helpers:

import LLVM.IR
import qualified LLVM.IROperand.Constructors as C

example :: IRBuilder ()
example =
  define i32 "add" [(i32, "a"), (i32, "b")] LExternal [] $ do
    beginBlock "entry"
    r <- add i32 (C.i32 1) (C.i32 2)
    ret r

Alternatively, use the OConstant and CInt constructors re-exported from LLVM.IROperand directly:

ret (OConstant (CInt 32 0))

Key concepts

IRBuilder, IRBuilderT
The builder monad. Run it with compileModule (produces LLVM assembly as Text) or buildModule (produces an IRModule). Use compileModuleWith and buildModuleWith for Either-based error handling.
define
Declare a function. Takes return type, name, [(type, paramName)] pairs, IRLinkage, [IRAttribute], and a monadic body computation.
beginBlock, block
Open a new basic block. Use block inside mdo notation to capture the generated label for use as a branch target — see the extended example.
Instruction constructors
Re-exported from LLVM.IRInstruction.Constructors. Each function (e.g. add, load, icmp, phi, call) emits one instruction and returns the result as an IROperand.
ret, br, condbr, switch, unreachable
Terminators from LLVM.IRTerminator.Constructors. Every basic block must end with exactly one terminator.
Type constructors
From LLVM.IRType.Constructors: i1, i8, i16, i32, i64, i128, ptr, void, float, double, struct, array, vector, fun, named.
emitAnnotation, comment, commentBlock
Emit a stand-alone comment into the current block. comment and commentBlock construct an IRAnnotation value to pass to emitAnnotation.
(<##>), withComment
Attach an inline comment to an instruction. (<##>) is the idiomatic operator form — postfix, reads left-to-right:
result <- add i32 a b <##> "note"

withComment is the equivalent function form, convenient with $:

result <- withComment "note" $ add i32 a b
OLocal, OGlobal, OConstant
Construct operands. OLocal references a function parameter or previous instruction result by name — OLocal i32 "x" where "x" matches the declared parameter name or a binding captured with <-. OGlobal references a module-level value: OGlobal i64 "fact". OConstant wraps a constant: OConstant (CInt 32 0) or OConstant (CFloat 1.0). For brevity, use the helpers from Constructors imported qualified (e.g. C.i32 0, C.i64 1).

Invariants

The following rules must hold for every generated module:

  1. Every block needs a terminator. Each basic block must end with exactly one of: ret, retVoid, br, condbr, switch, unreachable. A block without a terminator raises BlockMissingTerminator at finalization. A block with two terminators raises BlockAlreadyTerminated.
  2. The first block is "entry". Always call beginBlock "entry" as the first statement inside every define body.
  3. Parameters are OLocal. A parameter declared as [(i32, "x")] in define is accessed as OLocal i32 "x". The name must match exactly.
  4. Results are SSA bindings. Capture instruction results with <- and pass the IROperand binding directly. Never reconstruct a result from a name string.
  5. Use mdo for forward references. Enable {-# LANGUAGE RecursiveDo #-} and use mdo when a phi source or branch target is a Haskell binding defined later in the block sequence. Use do when there are no such forward references.
  6. Declare before calling. Invoke declare or declareVarArg before any call or callVoid on external functions. Duplicate declarations are silently ignored.

Extended example

An iterative factorial using mdo for forward block references. The pattern loopLabel <- block "loop" captures the generated unique label so it can be referenced in branch targets and phi nodes that appear lexically earlier in the mdo block.

A phi node selects among its incoming pairs based on which predecessor block control arrived from: phi ty [(v1, "lbl1"), (v2, "lbl2")] returns v1 if the previous block was "lbl1", v2 if it was "lbl2".

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecursiveDo       #-}

import LLVM.IR
import qualified LLVM.IROperand.Constructors as C

factorial :: Text
factorial = compileModule "mymod" $
  define i64 "fact" [(i64, "n")] LExternal [] $ mdo
    beginBlock "entry"
    br loopLabel

    loopLabel <- block "loop"
    acc  <- phi i64 [(C.i64 1, "entry"),          (newAcc, bodyLabel)]
    n    <- phi i64 [(OLocal i64 "n", "entry"),   (newN,   bodyLabel)]
    cond <- icmp ICmpSGt i64 n (C.i64 0)
    condbr cond bodyLabel exitLabel

    bodyLabel <- block "body"
    newAcc <- mul i64 acc n
    newN   <- sub i64 n (C.i64 1)
    br loopLabel

    exitLabel <- block "exit"
    ret acc

Module reference

LLVM.IRBuilder
Builder monad and compilation functions: compileModule, buildModule, compileModuleWith, buildModuleWith, define, beginBlock, block, emitInstruction, emitAnnotation, emitTerminator, emitGlobal, emitTypeDecl, declare, declareVarArg, and the (<##>) inline-comment operator.
LLVM.IRBuilder.Error
IRBuilderError type and displayError for programs that use explicit error handling via compileModuleWith or buildModuleWith.
LLVM.IRInstruction
IR instruction data types and condition codes: IRICmpCond, IRFCmpCond, IRTailMarker, IRInstrOp, IRInstruction.
LLVM.IRInstruction.Constructors
Instruction smart constructors: add, sub, mul, sdiv, udiv, load, store, gep, call, callVoid, icmp, fcmp, phi, select, bitcast, sext, zext, trunc, alloca, freeze, atomicRMW, cmpXchg, fence, and more.
LLVM.IRTerminator.Constructors
Block terminators: ret, retVoid, br, condbr, switch, unreachable.
LLVM.IRType
The IRType algebraic data type and the IRName type alias (type IRName = Text).
LLVM.IRType.Constructors
Type smart constructors: i1, i8, i16, i32, i64, i128, ptr, void, float, double, struct, array, vector, fun, named.
LLVM.IRModule
Module-level IR data types (IRModule, IRFunction, IRBlock, IRGlobal, IRBlockItem) and validation (verifyModule, typeCheckModule). IRLinkage values: LExternal (visible outside module), LInternal (module-local), LPrivate (not in symbol table). IRAttribute values: NoReturn, NoUnwind, ReadOnly, ReadNone, AlwaysInline, NoInline, TailCall, MustTailCall, Cold, Hot, InlineHint, NoAlias, GC "name".
LLVM.IROperand
Operand and constant data types: IROperand, IRConstant, IRTerminator. Helper functions: operandType, constantType, opComponents.
LLVM.IRAnnotation
The IRAnnotation type (Comment, CommentBlock).
LLVM.IRAnnotation.Constructors
Annotation helpers: comment, commentBlock, withComment. The (<##>) operator comes from IRBuilder.
LLVM.IROperand.Constructors
Integer and floating-point operand constants (i32, i64, float, local, global, etc.). Not re-exported here — import this module qualified to avoid collisions with the type constructors above.
LLVM.IR.Examples
Complete, runnable examples: helloWorld, addNumbers, and factorial.
Synopsis

Builder monad and compilation

Instruction types and condition codes

data IRICmpCond Source #

Condition codes for the icmp instruction.

data IRInstrOp Source #

All supported IR instruction operations.

Instances

Instances details
Show IRInstrOp Source # 
Instance details

Defined in LLVM.IRInstruction

Eq IRInstrOp Source # 
Instance details

Defined in LLVM.IRInstruction

Ord IRInstrOp Source # 
Instance details

Defined in LLVM.IRInstruction

data IRInstruction a Source #

Instances

Instances details
Show a => Show (IRInstruction a) Source # 
Instance details

Defined in LLVM.IRInstruction

Eq a => Eq (IRInstruction a) Source # 
Instance details

Defined in LLVM.IRInstruction

Ord a => Ord (IRInstruction a) Source # 
Instance details

Defined in LLVM.IRInstruction

Instruction constructors

Terminator constructors

Type system

IR data types

Annotations

comment :: Text -> IRAnnotation Source #

Create a single-line comment annotation.

Example:

emitAnnotation (comment "This is a comment")

Output:

; This is a comment

commentBlock :: [Text] -> IRAnnotation Source #

Create a multi-line comment block annotation.

Example:

emitAnnotation (commentBlock ["Line 1", "Line 2", "Line 3"])

Output:

; Line 1
; Line 2
; Line 3

withComment :: MonadIRBuilder m => Text -> m a -> m a Source #

Attach an inline comment to the result of a builder action.

Example:

reg <- withComment "comment explaining this" $ add i32 a b

Output:

%reg = add i32 %a, %b  ; comment explaining this