Build status for all platforms: Commercial support:
This directory contains the JavaCPP Presets module for:
- LLVM 19.1.3 http://llvm.org/
Please refer to the parent README.md file for more detailed information about the JavaCPP Presets.
Java API documentation is available here:
∗ Bindings are currently available only for the C APIs of LLVM and Clang.
∗ In the case of Clang, we might need to disable crash recovery with the LIBCLANG_DISABLE_CRASH_RECOVERY=1
environment variable to prevent clashes with the JVM's own signal handlers.
Here is a simple example showing how to calculate the factorial of a number with LLVM, initially based on this C source file:
We can use Maven 3 to download and install automatically all the class files as well as the native binaries. To run this sample code, after creating the pom.xml
and Factorial.java
source files below, simply execute on the command line:
$ mvn compile exec:java
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.bytedeco.llvm</groupId>
<artifactId>Factorial</artifactId>
<version>1.5.11</version>
<properties>
<exec.mainClass>Factorial</exec.mainClass>
</properties>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>llvm-platform</artifactId>
<version>19.1.3-1.5.11</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>.</sourceDirectory>
</build>
</project>
This example is based on MCJIT. There is a newer alternative called ORC. You can find an example using ORC here.
import org.bytedeco.javacpp.*;
import org.bytedeco.llvm.LLVM.*;
import static org.bytedeco.llvm.global.LLVM.*;
public class Factorial {
// a 'char *' used to retrieve error messages from LLVM
private static final BytePointer error = new BytePointer();
public static void main(String[] args) {
// Stage 1: Initialize LLVM components
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
// Stage 2: Build the factorial function.
LLVMContextRef context = LLVMContextCreate();
LLVMModuleRef module = LLVMModuleCreateWithNameInContext("factorial", context);
LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);
LLVMTypeRef i32Type = LLVMInt32TypeInContext(context);
LLVMTypeRef factorialType = LLVMFunctionType(i32Type, i32Type, /* argumentCount */ 1, /* isVariadic */ 0);
LLVMValueRef factorial = LLVMAddFunction(module, "factorial", factorialType);
LLVMSetFunctionCallConv(factorial, LLVMCCallConv);
LLVMValueRef n = LLVMGetParam(factorial, /* parameterIndex */0);
LLVMValueRef zero = LLVMConstInt(i32Type, 0, /* signExtend */ 0);
LLVMValueRef one = LLVMConstInt(i32Type, 1, /* signExtend */ 0);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(context, factorial, "entry");
LLVMBasicBlockRef ifFalse = LLVMAppendBasicBlockInContext(context, factorial, "if_false");
LLVMBasicBlockRef exit = LLVMAppendBasicBlockInContext(context, factorial, "exit");
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef condition = LLVMBuildICmp(builder, LLVMIntEQ, n, zero, "condition = n == 0");
LLVMBuildCondBr(builder, condition, exit, ifFalse);
LLVMPositionBuilderAtEnd(builder, ifFalse);
LLVMValueRef nMinusOne = LLVMBuildSub(builder, n, one, "nMinusOne = n - 1");
PointerPointer<Pointer> arguments = new PointerPointer<>(1)
.put(0, nMinusOne);
LLVMValueRef factorialResult = LLVMBuildCall2(builder, factorialType, factorial, arguments, 1, "factorialResult = factorial(nMinusOne)");
LLVMValueRef resultIfFalse = LLVMBuildMul(builder, n, factorialResult, "resultIfFalse = n * factorialResult");
LLVMBuildBr(builder, exit);
LLVMPositionBuilderAtEnd(builder, exit);
LLVMValueRef phi = LLVMBuildPhi(builder, i32Type, "result");
PointerPointer<Pointer> phiValues = new PointerPointer<>(2)
.put(0, one)
.put(1, resultIfFalse);
PointerPointer<Pointer> phiBlocks = new PointerPointer<>(2)
.put(0, entry)
.put(1, ifFalse);
LLVMAddIncoming(phi, phiValues, phiBlocks, /* pairCount */ 2);
LLVMBuildRet(builder, phi);
// Print generated LLVM-IR to console (optional)
LLVMDumpModule(module);
// Stage 3: Verify the module using LLVMVerifier
if (LLVMVerifyModule(module, LLVMPrintMessageAction, error) != 0) {
LLVMDisposeMessage(error);
return;
}
// Stage 4: Create a pass pipeline using the legacy pass manager
LLVMPassManagerRef pm = LLVMCreatePassManager();
LLVMRunPassManager(pm, module);
// Stage 5: Execute the code using MCJIT
LLVMExecutionEngineRef engine = new LLVMExecutionEngineRef();
LLVMMCJITCompilerOptions options = new LLVMMCJITCompilerOptions();
if (LLVMCreateMCJITCompilerForModule(engine, module, options, 3, error) != 0) {
System.err.println("Failed to create JIT compiler: " + error.getString());
LLVMDisposeMessage(error);
return;
}
LLVMGenericValueRef argument = LLVMCreateGenericValueOfInt(i32Type, 10, /* signExtend */ 0);
LLVMGenericValueRef result = LLVMRunFunction(engine, factorial, /* argumentCount */ 1, argument);
System.out.println();
System.out.println("Running factorial(10) with MCJIT...");
System.out.println("Result: " + LLVMGenericValueToInt(result, /* signExtend */ 0));
// Stage 6: Dispose of the allocated resources
LLVMDisposeExecutionEngine(engine);
LLVMDisposePassManager(pm);
LLVMDisposeBuilder(builder);
LLVMContextDispose(context);
}
}
More samples showing off LLVM usage from Java can be found in the samples/
subdirectory.