Skip to content

Commit

Permalink
Misc missing builder, engine, and target machine methods
Browse files Browse the repository at this point in the history
  • Loading branch information
TheDan64 committed Oct 6, 2017
1 parent 8c7dcf9 commit 355a238
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 5 deletions.
44 changes: 43 additions & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use either::Either;
use llvm_sys::core::{LLVMBuildAdd, LLVMBuildAlloca, LLVMBuildAnd, LLVMBuildArrayAlloca, LLVMBuildArrayMalloc, LLVMBuildBr, LLVMBuildCall, LLVMBuildCast, LLVMBuildCondBr, LLVMBuildExtractValue, LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFDiv, LLVMBuildFence, LLVMBuildFMul, LLVMBuildFNeg, LLVMBuildFree, LLVMBuildFSub, LLVMBuildGEP, LLVMBuildICmp, LLVMBuildInsertValue, LLVMBuildIsNotNull, LLVMBuildIsNull, LLVMBuildLoad, LLVMBuildMalloc, LLVMBuildMul, LLVMBuildNeg, LLVMBuildNot, LLVMBuildOr, LLVMBuildPhi, LLVMBuildPointerCast, LLVMBuildRet, LLVMBuildRetVoid, LLVMBuildStore, LLVMBuildSub, LLVMBuildUDiv, LLVMBuildUnreachable, LLVMBuildXor, LLVMDisposeBuilder, LLVMGetElementType, LLVMGetInsertBlock, LLVMGetReturnType, LLVMGetTypeKind, LLVMInsertIntoBuilder, LLVMPositionBuilderAtEnd, LLVMTypeOf, LLVMSetTailCall, LLVMBuildExtractElement, LLVMBuildInsertElement, LLVMBuildIntToPtr, LLVMBuildPtrToInt, LLVMInsertIntoBuilderWithName, LLVMClearInsertionPosition, LLVMCreateBuilder, LLVMPositionBuilder, LLVMPositionBuilderBefore, LLVMBuildAggregateRet, LLVMBuildStructGEP, LLVMBuildInBoundsGEP, LLVMBuildPtrDiff, LLVMBuildNSWAdd, LLVMBuildNUWAdd, LLVMBuildNSWSub, LLVMBuildNUWSub, LLVMBuildNSWMul, LLVMBuildNUWMul, LLVMBuildSDiv, LLVMBuildSRem, LLVMBuildURem, LLVMBuildFRem, LLVMBuildNSWNeg, LLVMBuildNUWNeg, LLVMBuildFPToUI, LLVMBuildFPToSI, LLVMBuildSIToFP, LLVMBuildUIToFP, LLVMBuildFPTrunc, LLVMBuildFPExt, LLVMBuildIntCast, LLVMBuildFPCast, LLVMBuildSExtOrBitCast, LLVMBuildZExtOrBitCast, LLVMBuildTruncOrBitCast, LLVMBuildSwitch, LLVMAddCase, LLVMBuildShl, LLVMBuildAShr, LLVMBuildLShr, LLVMBuildGlobalString, LLVMBuildGlobalStringPtr};
use llvm_sys::core::{LLVMBuildAdd, LLVMBuildAlloca, LLVMBuildAnd, LLVMBuildArrayAlloca, LLVMBuildArrayMalloc, LLVMBuildBr, LLVMBuildCall, LLVMBuildCast, LLVMBuildCondBr, LLVMBuildExtractValue, LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFDiv, LLVMBuildFence, LLVMBuildFMul, LLVMBuildFNeg, LLVMBuildFree, LLVMBuildFSub, LLVMBuildGEP, LLVMBuildICmp, LLVMBuildInsertValue, LLVMBuildIsNotNull, LLVMBuildIsNull, LLVMBuildLoad, LLVMBuildMalloc, LLVMBuildMul, LLVMBuildNeg, LLVMBuildNot, LLVMBuildOr, LLVMBuildPhi, LLVMBuildPointerCast, LLVMBuildRet, LLVMBuildRetVoid, LLVMBuildStore, LLVMBuildSub, LLVMBuildUDiv, LLVMBuildUnreachable, LLVMBuildXor, LLVMDisposeBuilder, LLVMGetElementType, LLVMGetInsertBlock, LLVMGetReturnType, LLVMGetTypeKind, LLVMInsertIntoBuilder, LLVMPositionBuilderAtEnd, LLVMTypeOf, LLVMSetTailCall, LLVMBuildExtractElement, LLVMBuildInsertElement, LLVMBuildIntToPtr, LLVMBuildPtrToInt, LLVMInsertIntoBuilderWithName, LLVMClearInsertionPosition, LLVMCreateBuilder, LLVMPositionBuilder, LLVMPositionBuilderBefore, LLVMBuildAggregateRet, LLVMBuildStructGEP, LLVMBuildInBoundsGEP, LLVMBuildPtrDiff, LLVMBuildNSWAdd, LLVMBuildNUWAdd, LLVMBuildNSWSub, LLVMBuildNUWSub, LLVMBuildNSWMul, LLVMBuildNUWMul, LLVMBuildSDiv, LLVMBuildSRem, LLVMBuildURem, LLVMBuildFRem, LLVMBuildNSWNeg, LLVMBuildNUWNeg, LLVMBuildFPToUI, LLVMBuildFPToSI, LLVMBuildSIToFP, LLVMBuildUIToFP, LLVMBuildFPTrunc, LLVMBuildFPExt, LLVMBuildIntCast, LLVMBuildFPCast, LLVMBuildSExtOrBitCast, LLVMBuildZExtOrBitCast, LLVMBuildTruncOrBitCast, LLVMBuildSwitch, LLVMAddCase, LLVMBuildShl, LLVMBuildAShr, LLVMBuildLShr, LLVMBuildGlobalString, LLVMBuildGlobalStringPtr, LLVMBuildExactSDiv, LLVMBuildTrunc, LLVMBuildSExt, LLVMBuildZExt};
use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef};
use llvm_sys::{LLVMOpcode, LLVMTypeKind, LLVMAtomicOrdering};

Expand Down Expand Up @@ -264,6 +264,18 @@ impl Builder {
IntValue::new(value)
}

// TODO: Possibly make this generic over sign via struct metadata or subtypes
// SubType: <I>(&self, lhs: &IntValue<I>, rhs: &IntValue<I>, name: &str) -> IntValue<I> {
pub fn build_int_exact_signed_div(&self, lhs: &IntValue, rhs: &IntValue, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let value = unsafe {
LLVMBuildExactSDiv(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};

IntValue::new(value)
}

// TODO: Possibly make this generic over sign via struct metadata or subtypes
// SubType: <I>(&self, lhs: &IntValue<I>, rhs: &IntValue<I>, name: &str) -> IntValue<I> {
pub fn build_int_unsigned_rem(&self, lhs: &IntValue, rhs: &IntValue, name: &str) -> IntValue {
Expand All @@ -289,6 +301,16 @@ impl Builder {
IntValue::new(value)
}

pub fn build_int_s_extend(&self, int_value: &IntValue, int_type: &IntType, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let value = unsafe {
LLVMBuildSExt(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};

IntValue::new(value)
}

pub fn build_int_s_extend_or_bit_cast(&self, int_value: &IntValue, int_type: &IntType, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

Expand All @@ -299,6 +321,16 @@ impl Builder {
IntValue::new(value)
}

pub fn build_int_z_extend(&self, int_value: &IntValue, int_type: &IntType, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let value = unsafe {
LLVMBuildZExt(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};

IntValue::new(value)
}

pub fn build_int_z_extend_or_bit_cast(&self, int_value: &IntValue, int_type: &IntType, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

Expand All @@ -309,6 +341,16 @@ impl Builder {
IntValue::new(value)
}

pub fn build_int_truncate(&self, int_value: &IntValue, int_type: &IntType, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let value = unsafe {
LLVMBuildTrunc(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};

IntValue::new(value)
}

pub fn build_int_truncate_or_bit_cast(&self, int_value: &IntValue, int_type: &IntType, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

Expand Down
11 changes: 9 additions & 2 deletions src/execution_engine.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use llvm_sys::core::LLVMDisposeMessage;
use llvm_sys::execution_engine::{LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, LLVMRunFunction, LLVMRunFunctionAsMain, LLVMDisposeExecutionEngine, LLVMGetFunctionAddress, LLVMAddModule, LLVMFindFunction, LLVMLinkInMCJIT, LLVMLinkInInterpreter, LLVMRemoveModule, LLVMGenericValueRef};
use llvm_sys::execution_engine::{LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, LLVMRunFunction, LLVMRunFunctionAsMain, LLVMDisposeExecutionEngine, LLVMGetFunctionAddress, LLVMAddModule, LLVMFindFunction, LLVMLinkInMCJIT, LLVMLinkInInterpreter, LLVMRemoveModule, LLVMGenericValueRef, LLVMFreeMachineCodeForFunction, LLVMGetPointerToGlobal};

use module::Module;
use targets::TargetData;
use values::{AsValueRef, FunctionValue, GenericValue};
use values::{AsValueRef, FunctionValue, GenericValue, GlobalValue};

use std::ffi::{CStr, CString};
use std::mem::{forget, uninitialized, zeroed};
Expand All @@ -26,6 +26,7 @@ impl ExecutionEngine {
pub(crate) fn new(execution_engine: LLVMExecutionEngineRef, jit_mode: bool) -> ExecutionEngine {
assert!(!execution_engine.is_null());

// REVIEW: Will we have to do this for LLVMGetExecutionEngineTargetMachine too?
let target_data = unsafe {
LLVMGetExecutionEngineTargetData(execution_engine)
};
Expand Down Expand Up @@ -187,6 +188,12 @@ impl ExecutionEngine {
LLVMRunFunctionAsMain(self.execution_engine, function.as_value_ref(), args.len() as u32, args.as_ptr(), env_p.as_ptr()); // REVIEW: usize to u32 cast ok??
}
}

pub fn free_fn_machine_code(&self, function: &FunctionValue) {
unsafe {
LLVMFreeMachineCodeForFunction(self.execution_engine, function.as_value_ref())
}
}
}

// Modules owned by the EE will be discarded by the EE so we don't
Expand Down
14 changes: 13 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub mod types;
pub mod values;

use llvm_sys::{LLVMIntPredicate, LLVMRealPredicate, LLVMVisibility, LLVMThreadLocalMode, LLVMDLLStorageClass};
use llvm_sys::support::LLVMLoadLibraryPermanently;

use std::ffi::CString;

// TODO: Probably move into error handling module
pub fn enable_llvm_pretty_stack_trace() {
Expand All @@ -38,6 +41,15 @@ pub fn is_multithreaded() -> bool {
}
}

// TODO: Move
pub fn load_library_permanently(filename: &str) -> bool {
let filename = CString::new(filename).expect("Conversion to CString failed unexpectedly");

unsafe {
LLVMLoadLibraryPermanently(filename.as_ptr()) == 1
}
}

// TODO: Move to better location?
// REVIEW: Not sure how safe this is. What happens when you make an llvm call after
// shutdown_llvm has been called?
Expand Down Expand Up @@ -127,7 +139,7 @@ impl FloatPredicate {


/// Defines the optimization level used to compile a `Module`.
///
///
/// # Remarks
/// See also: http://llvm.org/doxygen/CodeGen_8h_source.html
#[repr(u32)]
Expand Down
68 changes: 67 additions & 1 deletion src/targets.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use llvm_sys::core::LLVMDisposeMessage;
use llvm_sys::target::{LLVMTargetDataRef, LLVMCopyStringRepOfTargetData, LLVMSizeOfTypeInBits, LLVMCreateTargetData, LLVMAddTargetData, LLVMByteOrder, LLVMPointerSize, LLVMByteOrdering, LLVMStoreSizeOfType, LLVMABISizeOfType, LLVMABIAlignmentOfType, LLVMCallFrameAlignmentOfType, LLVMPreferredAlignmentOfType, LLVMPreferredAlignmentOfGlobal, LLVMElementAtOffset, LLVMOffsetOfElement, LLVMDisposeTargetData, LLVMPointerSizeForAS, LLVMIntPtrType, LLVMIntPtrTypeForAS, LLVMIntPtrTypeInContext, LLVMIntPtrTypeForASInContext};
use llvm_sys::target_machine::{LLVMGetFirstTarget, LLVMTargetRef, LLVMGetNextTarget, LLVMGetTargetFromName, LLVMGetTargetFromTriple, LLVMGetTargetName, LLVMGetTargetDescription, LLVMTargetHasJIT, LLVMTargetHasTargetMachine, LLVMTargetHasAsmBackend, LLVMTargetMachineRef, LLVMDisposeTargetMachine, LLVMGetTargetMachineTarget, LLVMGetTargetMachineTriple, LLVMSetTargetMachineAsmVerbosity, LLVMCreateTargetMachine, LLVMGetTargetMachineCPU, LLVMGetTargetMachineFeatureString, LLVMGetDefaultTargetTriple, LLVMAddAnalysisPasses, LLVMCodeGenOptLevel, LLVMCodeModel, LLVMRelocMode};
use llvm_sys::target_machine::{LLVMGetFirstTarget, LLVMTargetRef, LLVMGetNextTarget, LLVMGetTargetFromName, LLVMGetTargetFromTriple, LLVMGetTargetName, LLVMGetTargetDescription, LLVMTargetHasJIT, LLVMTargetHasTargetMachine, LLVMTargetHasAsmBackend, LLVMTargetMachineRef, LLVMDisposeTargetMachine, LLVMGetTargetMachineTarget, LLVMGetTargetMachineTriple, LLVMSetTargetMachineAsmVerbosity, LLVMCreateTargetMachine, LLVMGetTargetMachineCPU, LLVMGetTargetMachineFeatureString, LLVMGetDefaultTargetTriple, LLVMAddAnalysisPasses, LLVMCodeGenOptLevel, LLVMCodeModel, LLVMRelocMode, LLVMCodeGenFileType, LLVMTargetMachineEmitToMemoryBuffer, LLVMTargetMachineEmitToFile};

use OptimizationLevel;
use context::Context;
use data_layout::DataLayout;
use memory_buffer::MemoryBuffer;
use module::Module;
use passes::PassManager;
use types::{AnyType, AsTypeRef, StructType, PointerType};
use values::{AsValueRef, GlobalValue};

use std::default::Default;
use std::ffi::{CStr, CString};
use std::mem::zeroed;
use std::path::Path;
use std::ptr;

#[derive(Debug, PartialEq, Eq)]
Expand All @@ -32,6 +35,22 @@ pub enum RelocMode {
DynamicNoPic,
}


#[derive(Debug, PartialEq, Eq)]
pub enum FileType {
Assembly,
Object,
}

impl FileType {
fn as_llvm_file_type(&self) -> LLVMCodeGenFileType {
match *self {
FileType::Assembly => LLVMCodeGenFileType::LLVMAssemblyFile,
FileType::Object => LLVMCodeGenFileType::LLVMObjectFile,
}
}
}

// TODO: Doc: Base gets you TargetMachine support, machine_code gets you asm_backend
#[derive(Debug, PartialEq, Eq)]
pub struct InitializationConfig {
Expand Down Expand Up @@ -707,6 +726,53 @@ impl TargetMachine {
LLVMAddAnalysisPasses(self.target_machine, pass_manager.pass_manager)
}
}

pub fn write_to_memory_buffer(&self, module: &Module, file_type: FileType) -> Result<MemoryBuffer, String> {
let mut memory_buffer = ptr::null_mut();
let mut err_str = unsafe { zeroed() };
let return_code = unsafe {
LLVMTargetMachineEmitToMemoryBuffer(self.target_machine, module.module, file_type.as_llvm_file_type(), &mut err_str, &mut memory_buffer)
};

// TODO: Verify 1 is error code (LLVM can be inconsistent)
if return_code == 1 {
let rust_str = unsafe {
let rust_str = CStr::from_ptr(err_str).to_string_lossy().into_owned();

LLVMDisposeMessage(err_str);

rust_str
};

return Err(rust_str);
}

Ok(MemoryBuffer::new(memory_buffer))
}

pub fn write_to_file(&self, module: &Module, file_type: FileType, path: &Path) -> Result<(), String> {
let path = path.to_str().expect("Did not find a valid Unicode path string");
let mut err_str = unsafe { zeroed() };
let return_code = unsafe {
// REVIEW: Why does LLVM need a mutable reference to path...?
LLVMTargetMachineEmitToFile(self.target_machine, module.module, path.as_ptr() as *mut i8, file_type.as_llvm_file_type(), &mut err_str)
};

// TODO: Verify 1 is error code (LLVM can be inconsistent)
if return_code == 1 {
let rust_str = unsafe {
let rust_str = CStr::from_ptr(err_str).to_string_lossy().into_owned();

LLVMDisposeMessage(err_str);

rust_str
};

return Err(rust_str);
}

Ok(())
}
}

impl Drop for TargetMachine {
Expand Down

0 comments on commit 355a238

Please sign in to comment.