diff --git a/src/builder.rs b/src/builder.rs index f5a3ec4cf14..f7b25930c96 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -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}; @@ -264,6 +264,18 @@ impl Builder { IntValue::new(value) } + // TODO: Possibly make this generic over sign via struct metadata or subtypes + // SubType: (&self, lhs: &IntValue, rhs: &IntValue, name: &str) -> IntValue { + 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: (&self, lhs: &IntValue, rhs: &IntValue, name: &str) -> IntValue { pub fn build_int_unsigned_rem(&self, lhs: &IntValue, rhs: &IntValue, name: &str) -> IntValue { @@ -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"); @@ -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"); @@ -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"); diff --git a/src/execution_engine.rs b/src/execution_engine.rs index a613b8c2f37..6fceecdad9e 100644 --- a/src/execution_engine.rs +++ b/src/execution_engine.rs @@ -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}; @@ -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) }; @@ -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 diff --git a/src/lib.rs b/src/lib.rs index 7aad5cd42cb..c0c745b9c0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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() { @@ -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? @@ -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)] diff --git a/src/targets.rs b/src/targets.rs index 95f5fd8ae3b..318ad0f4c56 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -1,10 +1,12 @@ 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}; @@ -12,6 +14,7 @@ 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)] @@ -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 { @@ -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 { + 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 {