Skip to content

Commit

Permalink
* Add samples using LLVM modules to deal with bitcode and object fil…
Browse files Browse the repository at this point in the history
…es (pull #1016)
  • Loading branch information
junlarsen committed Mar 11, 2021
1 parent 7b0fea8 commit 32d981f
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

* Add samples using LLVM modules to deal with bitcode and object files ([pull #1016](https://github.com/bytedeco/javacpp-presets/pull/1016))

### March 8, 2021 version 1.5.5
* Bundle LLD executable in presets for LLVM as required by TVM on Windows
* Prevent `public static final` objects from getting deallocated by `PointerScope` ([issue bytedeco/javacv#1599](https://github.com/bytedeco/javacv/issues/1599))
Expand Down
84 changes: 84 additions & 0 deletions llvm/samples/llvm/LLVMEmitObjectAndBitcodeFiles.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import org.bytedeco.javacpp.*;
import org.bytedeco.llvm.LLVM.*;

import static org.bytedeco.llvm.global.LLVM.*;

/**
* This is an example which shows how you can dump both object and bitcode file
* from a LLVM module in JavaCPP.
*
* It produces two files, add.o and add.bc. The bitcode file can be used in the
* LLVMRunFunctionFromBitcode.java sample. See that file for details.
*/
public class LLVMEmitObjectAndBitcodeFiles {
public static void main(String[] unused) {
// This example uses the target you're running on, enable
// more targets as necessary
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
LLVMInitializeNativeDisassembler();
LLVMInitializeNativeTarget();

LLVMContextRef context = LLVMContextCreate();
LLVMModuleRef module = LLVMModuleCreateWithNameInContext("test", context);
LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);
BytePointer error = new BytePointer((Pointer) null);

// Construct the "i32 add(i32, i32)" function
LLVMTypeRef i32 = LLVMInt32TypeInContext(context);
LLVMTypeRef[] args = {i32, i32};
PointerPointer<LLVMTypeRef> args_ptr = new PointerPointer<>(args);
LLVMTypeRef add_type = LLVMFunctionType(i32, args_ptr, 2, 0);
LLVMValueRef add = LLVMAddFunction(module, "add", add_type);
LLVMSetFunctionCallConv(add, LLVMCCallConv);
args_ptr.deallocate();

// Build the IR for the add function
LLVMBasicBlockRef entrypoint = LLVMAppendBasicBlock(add, "Entry");
LLVMPositionBuilderAtEnd(builder, entrypoint);

LLVMValueRef a = LLVMGetParam(add, 0);
LLVMValueRef b = LLVMGetParam(add, 1);
LLVMValueRef sum = LLVMBuildAdd(builder, a, b, "sum");
LLVMBuildRet(builder, sum);

LLVMDumpModule(module);

// Emit the module to an object file
BytePointer triple_ptr = LLVMGetDefaultTargetTriple();
String triple = triple_ptr.getString();
triple_ptr.deallocate();
LLVMSetTarget(module, triple);

LLVMVerifyModule(module, LLVMAbortProcessAction, error);
// Don't handle any error because LLVMAbortProcessAction was used

// Note: Replace with your own architecture if you're not running on x86 64bit
LLVMTargetRef target = LLVMGetTargetFromName("x86-64");
String cpu = "generic";
String cpu_features = "";
int optimization_level = 0;

LLVMTargetMachineRef machine = LLVMCreateTargetMachine(target, triple, cpu, cpu_features, optimization_level,
LLVMRelocDefault, LLVMCodeModelDefault);
BytePointer output = new BytePointer("add.o");

if (LLVMTargetMachineEmitToFile(machine, module, output, LLVMObjectFile, error) != 0) {
String msg = error.getString();
LLVMDisposeMessage(error);
throw new RuntimeException(msg);
}
error.deallocate();

// Emit to bitcode
if (LLVMWriteBitcodeToFile(module, "./add.bc") != 0) {
throw new RuntimeException("failed to write bitcode to file");
}

// Clean up resources
LLVMDisposeMessage(error);
LLVMDisposeBuilder(builder);
LLVMDisposeModule(module);
LLVMContextDispose(context);
}
}
67 changes: 67 additions & 0 deletions llvm/samples/llvm/LLVMRunFunctionFromBitcode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import org.bytedeco.javacpp.*;
import org.bytedeco.llvm.LLVM.*;

import static org.bytedeco.llvm.global.LLVM.*;

/**
* This is an example which loads a LLVM module from a bitcode (.bc) file and
* runs a function inside it using the LLVM interpreter.
*
* The sample should be used in conjunction with LLVMEmitObjectAndBitcodeFiles.java
* which is capable of producing the bitcode file this example uses.
*
* It loads a function named "add" from the bitcode file which has a signature of
* `i32 add(i32, i32)` which was created in the aforementioned Java file. It is then
* executed via the LLVM interpreter and the result is printed to stdout.
*/
public class LLVMRunFunctionFromBitcode {
public static void main(String[] unused) {
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
LLVMInitializeNativeDisassembler();
LLVMInitializeNativeTarget();

LLVMModuleRef module = new LLVMModuleRef();
LLVMMemoryBufferRef buffer = new LLVMMemoryBufferRef();
BytePointer error = new BytePointer((Pointer) null);

// Open file into memory buffer
if (LLVMCreateMemoryBufferWithContentsOfFile(new BytePointer("./add.bc"), buffer, error) != 0) {
String msg = error.getString();
LLVMDisposeMessage(error);
throw new RuntimeException(msg);
}

// Attempt to parse bitcode out of memory buffer
if (LLVMParseBitcode2(buffer, module) != 0) {
throw new RuntimeException("Failed to parse bitcode in module");
}

// Let's run the add function via the LLVM interpreter
LLVMExecutionEngineRef engine = new LLVMExecutionEngineRef();
if (LLVMCreateInterpreterForModule(engine, module, error) != 0) {
String msg = error.getString();
LLVMDisposeMessage(error);
throw new RuntimeException(msg);
}

LLVMValueRef add = LLVMGetNamedFunction(module, "add");
LLVMTypeRef i32 = LLVMInt32Type();
LLVMGenericValueRef[] args = new LLVMGenericValueRef[]{
LLVMCreateGenericValueOfInt(i32, 1000, 0),
LLVMCreateGenericValueOfInt(i32, 1, 0)
};
PointerPointer<LLVMGenericValueRef> args_ptr = new PointerPointer<>(args);
LLVMGenericValueRef result = LLVMRunFunction(engine, add, 2, args_ptr);
args_ptr.deallocate();

System.out.println("The result of add(1000, 1), loaded through membuffers and executed through LLVM " +
"interpreter is: " + LLVMGenericValueToInt(result, 0));

// Cleanup, the module is moved into the JIT compiler and released
// when we release the engine
LLVMDisposeMessage(error);
LLVMDisposeExecutionEngine(engine);
LLVMDisposeMemoryBuffer(buffer);
}
}

0 comments on commit 32d981f

Please sign in to comment.