-
Notifications
You must be signed in to change notification settings - Fork 737
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add samples using LLVM modules to deal with bitcode and object fil…
…es (pull #1016)
- Loading branch information
Showing
3 changed files
with
153 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |