llvm-node-bindings
v0.1.1
Published
TypeScript bindings for LLVM 22 codegen APIs
Maintainers
Readme
LLVM Bindings for Node.js
TypeScript/JavaScript bindings for LLVM 22 code generation APIs. Designed for building compilers, transpilers, and code generation tools in Node.js.
Features
- LLVM 22 Support: Built against LLVM 22.1.x with opaque pointer support
- Type-Safe: Full TypeScript definitions for all APIs
- Core IR Generation: Complete support for basic LLVM IR generation
- Contexts, Modules, Types (primitive, function, struct, pointer)
- Functions, Basic Blocks, Values
- IRBuilder with all common instructions (arithmetic, comparison, memory, control flow, calls)
- Output Formats: Generate LLVM IR text (.ll) and bitcode (.bc) files
- Memory Safe: Proper memory management using shared_ptr/weak_ptr for LLVM objects
Installation
Prerequisites
- Node.js: 16.x or later
- LLVM 22: Install LLVM 22.1.x
- macOS:
brew install llvm@22 - Ubuntu/Debian: Install from LLVM apt repository
- Windows: Download pre-built binaries from LLVM releases
- macOS:
- CMake: 3.15 or later
- C++17 compiler: clang++ or g++
Install
npm install llvm-node-bindingsThe native addon will be compiled during installation using cmake-js.
Quick Start
import llvm from 'llvm-node-bindings';
// Create context and module
const context = new llvm.LLVMContext();
const module = new llvm.Module('my_module', context);
const builder = new llvm.IRBuilder(context);
// Create a simple function: i32 @add(i32, i32)
const i32 = llvm.Type.getInt32Ty(context);
const fnType = llvm.FunctionType.get(i32, [i32, i32], false);
const addFunc = llvm.Function.create(fnType, 'external', 'add', module);
// Create entry block and generate IR
const entry = llvm.BasicBlock.create(context, 'entry', addFunc);
builder.setInsertionPoint(entry);
// Add two constants and return result
const a = builder.createConstInt(i32, 10);
const b = builder.createConstInt(i32, 20);
const sum = builder.createAdd(a, b);
builder.createRet(sum);
// Output LLVM IR
console.log(module.print());
// Write bitcode to file
module.writeBitcodeToFile('output.bc');API Reference
LLVMContext
The top-level container for all LLVM entities. Each context is independent.
const context = new llvm.LLVMContext();Module
A compilation unit containing functions and global variables.
const module = new llvm.Module('module_name', context);
const ir = module.print(); // Get LLVM IR as string
module.writeBitcodeToFile('out.bc'); // Write bitcode fileType
Base class for all LLVM types. Static factory methods for primitive types:
const voidTy = llvm.Type.getVoidTy(context);
const i1 = llvm.Type.getInt1Ty(context); // boolean
const i8 = llvm.Type.getInt8Ty(context);
const i16 = llvm.Type.getInt16Ty(context);
const i32 = llvm.Type.getInt32Ty(context);
const i64 = llvm.Type.getInt64Ty(context);
const f32 = llvm.Type.getFloatTy(context);
const f64 = llvm.Type.getDoubleTy(context);FunctionType
const fnType = llvm.FunctionType.get(
returnType, // Type
[param1, param2], // Type[]
false // isVarArg
);StructType
const structTy = llvm.StructType.get(
context,
[i32, i32, f64], // field types
false // isPacked
);PointerType
LLVM 22 uses opaque pointers (typed pointers are deprecated).
const ptrTy = llvm.PointerType.get(context, 0); // address space 0Function
const func = llvm.Function.create(
functionType, // FunctionType
'external', // linkage: 'external' | 'internal' | 'private'
'function_name', // string
module // Module
);BasicBlock
const bb = llvm.BasicBlock.create(context, 'entry', parentFunc);
const parent = bb.getParent(); // Get parent functionValue
Base class for all values. Methods available on all values:
const name = value.getName();
value.setName('new_name');
const type = value.getType();IRBuilder
Helper for generating LLVM instructions.
const builder = new llvm.IRBuilder(context);
builder.setInsertionPoint(basicBlock);Constants
const constInt = builder.createConstInt(type, value);Terminator Instructions
builder.createRetVoid();
builder.createRet(value);
builder.createBr(destBlock);
builder.createCondBr(condition, thenBlock, elseBlock);Arithmetic Instructions
builder.createAdd(lhs, rhs); // addition
builder.createSub(lhs, rhs); // subtraction
builder.createMul(lhs, rhs); // multiplication
builder.createSDiv(lhs, rhs); // signed division
builder.createUDiv(lhs, rhs); // unsigned division
builder.createSRem(lhs, rhs); // signed remainderBitwise Instructions
builder.createAnd(lhs, rhs); // bitwise AND
builder.createOr(lhs, rhs); // bitwise OR
builder.createXor(lhs, rhs); // bitwise XOR
builder.createShl(lhs, rhs); // left shift
builder.createLShr(lhs, rhs); // logical right shift
builder.createAShr(lhs, rhs); // arithmetic right shiftComparison Instructions
builder.createICmpEQ(lhs, rhs); // equal
builder.createICmpNE(lhs, rhs); // not equal
builder.createICmpSLT(lhs, rhs); // signed less than
builder.createICmpSLE(lhs, rhs); // signed less or equal
builder.createICmpSGT(lhs, rhs); // signed greater than
builder.createICmpSGE(lhs, rhs); // signed greater or equalMemory Instructions
const ptr = builder.createAlloca(type);
const val = builder.createLoad(type, ptr);
builder.createStore(value, ptr);GEP (GetElementPtr)
const elemPtr = builder.createGEP(baseType, ptr, [index1, index2]);Call Instruction
const result = builder.createCall(functionType, callee, [arg1, arg2]);Complete Example
import llvm from 'llvm-node-bindings';
import * as fs from 'fs';
// Setup
const context = new llvm.LLVMContext();
const module = new llvm.Module('example', context);
const builder = new llvm.IRBuilder(context);
// Types
const i32 = llvm.Type.getInt32Ty(context);
const i1 = llvm.Type.getInt1Ty(context);
// Function: i32 @main()
const mainType = llvm.FunctionType.get(i32, [], false);
const mainFunc = llvm.Function.create(mainType, 'external', 'main', module);
// Basic blocks
const entry = llvm.BasicBlock.create(context, 'entry', mainFunc);
const thenBB = llvm.BasicBlock.create(context, 'then', mainFunc);
const elseBB = llvm.BasicBlock.create(context, 'else', mainFunc);
const mergeBB = llvm.BasicBlock.create(context, 'merge', mainFunc);
// Entry block: allocate variable and branch
builder.setInsertionPoint(entry);
const xPtr = builder.createAlloca(i32);
const initialValue = builder.createConstInt(i32, 10);
builder.createStore(initialValue, xPtr);
const x = builder.createLoad(i32, xPtr);
const five = builder.createConstInt(i32, 5);
const cond = builder.createICmpSGT(x, five);
builder.createCondBr(cond, thenBB, elseBB);
// Then block
builder.setInsertionPoint(thenBB);
const twenty = builder.createConstInt(i32, 20);
const thenResult = builder.createAdd(x, twenty);
builder.createStore(thenResult, xPtr);
builder.createBr(mergeBB);
// Else block
builder.setInsertionPoint(elseBB);
const ten = builder.createConstInt(i32, 10);
const elseResult = builder.createMul(x, ten);
builder.createStore(elseResult, xPtr);
builder.createBr(mergeBB);
// Merge block
builder.setInsertionPoint(mergeBB);
const finalValue = builder.createLoad(i32, xPtr);
builder.createRet(finalValue);
// Output
fs.writeFileSync('output.ll', module.print());
module.writeBitcodeToFile('output.bc');Building from Source
git clone <repository-url>
cd llvm-node-bindings
npm install
npm run build
npm testTesting
npm test # Run all tests
npm test context.test.ts # Run specific testArchitecture
The bindings use a three-layer architecture:
- Native C++ Layer: NAPI wrappers around LLVM C++ APIs
- JavaScript Bridge: Node.js addon exposing wrapped classes
- TypeScript Definitions: Type-safe interface for TypeScript
Memory management uses shared_ptr for LLVMContext and weak_ptr for dependent objects, ensuring safe cleanup while respecting LLVM's ownership model.
LLVM 22 Notes
- Opaque Pointers: LLVM 22 uses opaque pointers. Use
PointerType::get(context, addressSpace)instead of typed pointers. - Constant Folding: LLVM automatically folds constant expressions (e.g.,
10 + 20becomes30at compile time).
Comparison with llvm-bindings v14
This is a fresh implementation for LLVM 22, not backward compatible with the v14 bindings at https://github.com/mohitk05/llvm-bindings:
- Targets LLVM 22 (vs LLVM 14)
- Uses opaque pointers (LLVM 22 requirement)
- Focused API surface for basic IR generation
- Modern C++17 and Node-API
- TDD approach with comprehensive test coverage
Requirements
- LLVM 22.1.x
- Node.js 16+
- CMake 3.15+
- C++17 compiler
License
MIT
Contributing
Contributions welcome! Please ensure:
- All tests pass (
npm test) - New features include tests
- Code follows existing style
Roadmap
Future enhancements may include:
- Global variables and constants
- Function attributes
- Additional instruction types (bitcast, phi, select)
- Optimization passes
- Target machine codegen
Support
For issues and questions, please file an issue on GitHub.
