Skip to content

swift-llvm-c/inkglide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Inkglide

It’s a New Kind of Glue for LLVM IR Design & Execution

Inkglide offers lightweight, type-safe Swift wrappers for the LLVM C APIs, allowing for safe and performant access to LLVM. Inkglide relies heavily on Swift’s ownership semantics and noncopyable types to ensure safety and correctness, so it’s recommended to be familiar with these concepts in Swift before using this library.

Considerations

Inkglide takes inspiration from multiple sources, including but limited to: Inkwell, Swifty-LLVM, LLVMSwift

See also: swift-llvm-bindings

Requirements

  • Swift 6.2
  • LLVM 21

Build

Prerequisites

  1. Install LLVM 21
  2. Install pkg-config

Setup pkg-config

  1. Create an llvm.pc file with the following template:
prefix=/path/to/llvm/installation
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: LLVM
Description: LLVM Compiler Infrastructure
Version: 21
Libs: -L${libdir} -lLLVM
Cflags: -I${includedir}
  1. Save this file to a pkgconfig directory (e.g., ~/.pkgconfig/ or /usr/local/lib/pkgconfig/)

  2. Add the pkgconfig directory to your environment:

export PKG_CONFIG_PATH=/path/to/pkgconfig:$PKG_CONFIG_PATH

Build and Test

  1. Build and run:
swift build -c release
swift test -c release

macOS-Specific Setup

  1. macOS only: If using Homebrew's LLVM, you may need to set the library path for Z3 (an LLVM dependency):
export DYLD_LIBRARY_PATH="/opt/homebrew/opt/z3/lib:$DYLD_LIBRARY_PATH"

Examples

Inkwell's example written with Inkglide:

import Inkglide

typealias SumFunc = @convention(c) (UInt64, UInt64, UInt64) -> UInt64

struct CodeGen: ~Copyable {
    let context: Context
    var module: Module
    var builder: Builder

    mutating func emitIR() {
        let int64Type = self.context.int64Type()
        let functionType = int64Type.functionType([int64Type, int64Type, int64Type], isVariadic: false)
        let function = module.addFunction(name: "sum", type: functionType)
        let basicBlock = self.context.appendBasicBlock(named: "entry", in: function)

        self.builder.positionAtEnd(of: basicBlock)

        let i = function.parameter(at: 0)!.intValue!
        let j = function.parameter(at: 1)!.intValue!
        let k = function.parameter(at: 2)!.intValue!

        var sum = self.builder.buildIntAdd(i, j, name: "sum")
        sum = self.builder.buildIntAdd(sum, k, name: "sum")

        _ = self.builder.buildReturn(sum)
    }
}

func main() throws {
    let context = Context()
    let module = Module(name: "sum", in: context)
    let builder = Builder(in: context)
    var codeGen = CodeGen(context: context, module: module, builder: builder)
    codeGen.emitIR()

    try Target.initializeNative()
    var jit = try OrcJIT()
    try jit.add(module: codeGen.module)
    let sum = try jit.getFunction(named: "sum", as: SumFunc.self)

    let i: UInt64 = 1
    let j: UInt64 = 2
    let k: UInt64 = 3

    print("\(i) + \(j) + \(k) = \(sum(i, j, k))")
    assert(sum(i, j, k) == i + j + k)
}

About

It’s a New Kind of Glue for LLVM IR Design & Execution

Resources

License

Stars

Watchers

Forks

Packages

No packages published