Skip to content

Commit

Permalink
Improvements to documentation (rust-lang#20)
Browse files Browse the repository at this point in the history
* Improvements to documentation
* Improved style a bit more
* Merged OptimizationLevel and CodeGenOptLevel, among other things
* Option<OptimizationLevel> -> OptimizationLevel with Default
  • Loading branch information
Grégoire Geis authored and TheDan64 committed Oct 5, 2017
1 parent d835d33 commit 8c7dcf9
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 61 deletions.
11 changes: 5 additions & 6 deletions examples/kaleidoscope/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use self::inkwell::passes::PassManager;
use self::inkwell::targets::{InitializationConfig, Target};
use self::inkwell::types::BasicType;
use self::inkwell::values::{BasicValue, FloatValue, FunctionValue, PointerValue};
use self::inkwell::FloatPredicate;
use self::inkwell::{OptimizationLevel, FloatPredicate};

use Token::*;

Expand Down Expand Up @@ -98,7 +98,6 @@ impl<'a> Lexer<'a> {
}

/// Lexes and returns the next `Token` from the source code.
#[allow(unused_variables)]
pub fn lex(&mut self) -> LexResult {
let chars = self.chars.deref_mut();
let src = self.input;
Expand Down Expand Up @@ -157,12 +156,12 @@ impl<'a> Lexer<'a> {
Ok(Token::Comment)
},

ch @ '.' | ch @ '0' ... '9' => {
'.' | '0' ... '9' => {
// Parse number literal
loop {
let ch = match chars.peek() {
Some(ch) => *ch,
None => { return Ok(Token::EOF); }
None => return Ok(Token::EOF)
};

// Parse float.
Expand All @@ -182,7 +181,7 @@ impl<'a> Lexer<'a> {
loop {
let ch = match chars.peek() {
Some(ch) => *ch,
None => { return Ok(Token::EOF); }
None => return Ok(Token::EOF)
};

// A word-like identifier only contains underscores and alphanumeric characters.
Expand Down Expand Up @@ -1341,7 +1340,7 @@ pub fn main() {
};

if is_anonymous {
let ee = module.create_jit_execution_engine(0).unwrap();
let ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();

let addr = match ee.get_function_address(name.as_str()) {
Ok(addr) => addr,
Expand Down
2 changes: 1 addition & 1 deletion src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ pub struct ContextRef {
}

impl ContextRef {
pub fn new(context: Context) -> Self {
pub(crate) fn new(context: Context) -> Self {
ContextRef {
context: Some(context),
}
Expand Down
21 changes: 21 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,27 @@ impl FloatPredicate {
}
}


/// Defines the optimization level used to compile a `Module`.
///
/// # Remarks
/// See also: http://llvm.org/doxygen/CodeGen_8h_source.html
#[repr(u32)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum OptimizationLevel {
None = 0,
Less = 1,
Default = 2,
Aggressive = 3
}

impl Default for OptimizationLevel {
/// Returns the default value for `OptimizationLevel`, namely `OptimizationLevel::Default`.
fn default() -> Self {
OptimizationLevel::Default
}
}

// REVIEW: Maybe this belongs in some sort of prelude?
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GlobalVisibility {
Expand Down
101 changes: 90 additions & 11 deletions src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ use std::mem::{forget, uninitialized, zeroed};
use std::path::Path;
use std::slice::from_raw_parts;

use OptimizationLevel;
use context::{Context, ContextRef};
use data_layout::DataLayout;
use execution_engine::ExecutionEngine;
use memory_buffer::MemoryBuffer;
use types::{AsTypeRef, BasicType, FunctionType, BasicTypeEnum};
use values::{AsValueRef, BasicValue, FunctionValue, GlobalValue, MetadataValue};
use values::{AsValueRef, FunctionValue, GlobalValue, MetadataValue};

// REVIEW: Maybe this should go into it's own module?
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
Expand All @@ -40,6 +41,19 @@ pub enum Linkage {
WeakODRLinkage,
}

/// Defines the address space in which a global will be inserted.
///
/// # Remarks
/// See also: http://llvm.org/doxygen/NVPTXBaseInfo_8h_source.html
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum AddressSpace {
Generic = 0,
Global = 1,
Shared = 3,
Const = 4,
Local = 5
}

impl Linkage {
pub(crate) fn new(linkage: LLVMLinkage) -> Self {
match linkage {
Expand Down Expand Up @@ -86,6 +100,8 @@ impl Linkage {
}
}

/// Represents a reference to an LLVM `Module`.
/// The underlying module will be disposed when dropping this object.
#[derive(Debug, PartialEq, Eq)]
pub struct Module {
pub(crate) module: LLVMModuleRef,
Expand Down Expand Up @@ -129,12 +145,31 @@ impl Module {
Module::new(module)
}

// TODOC: LLVM will default linkage to ExternalLinkage (at least in 3.7)
pub fn add_function(&self, name: &str, return_type: &FunctionType, linkage: Option<&Linkage>) -> FunctionValue {
/// Creates a function given its `name` and `ty`, adds it to the `Module`
/// and returns it.
///
/// An optional `linkage` can be specified, without which the default value
/// `Linkage::ExternalLinkage` will be used.
///
/// # Example
/// ```
/// use inkwell::context::Context;
/// use inkwell::module::{Module, Linkage};
///
/// let context = Context::get_global();
/// let module = Module::create("my_module");
///
/// let fn_type = context.f32_type().fn_type(&[], false);
/// let fn_val = module.add_function("my_function", &fn_type, None);
///
/// assert_eq!(fn_val.get_name().to_str(), Ok("my_function"));
/// assert_eq!(fn_val.get_linkage(), Linkage::ExternalLinkage);
/// ```
pub fn add_function(&self, name: &str, ty: &FunctionType, linkage: Option<&Linkage>) -> FunctionValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let value = unsafe {
LLVMAddFunction(self.module, c_string.as_ptr(), return_type.as_type_ref())
LLVMAddFunction(self.module, c_string.as_ptr(), ty.as_type_ref())
};

if let Some(linkage) = linkage {
Expand All @@ -146,6 +181,24 @@ impl Module {
FunctionValue::new(value).expect("add_function should always succeed in adding a new function")
}

/// Gets the `Context` from which this `Module` originates.
///
/// # Example
/// ```
/// use inkwell::context::{Context, ContextRef};
/// use inkwell::module::Module;
///
/// let global_context = Context::get_global();
/// let global_module = Module::create("my_global_module");
///
/// assert_eq!(global_module.get_context(), global_context);
///
/// let local_context = Context::create();
/// let local_module = local_context.create_module("my_module");
///
/// assert_eq!(*local_module.get_context(), local_context);
/// assert_ne!(local_context, *global_context);
/// ```
pub fn get_context(&self) -> ContextRef {
let context = unsafe {
LLVMGetModuleContext(self.module)
Expand Down Expand Up @@ -210,15 +263,29 @@ impl Module {
}
}

// TODOC: EE must *own* modules and deal out references
// REVIEW: Looking at LLVM source, opt_level seems to be casted into a targets::CodeGenOptLevel
// or LLVM equivalent anyway
pub fn create_jit_execution_engine(self, opt_level: u32) -> Result<ExecutionEngine, String> {
/// Consumes this `Module`, and creates a JIT `ExecutionEngine` from it.
///
/// # Example
/// ```no_run
/// use inkwell::OptimizationLevel;
/// use inkwell::context::Context;
/// use inkwell::module::Module;
/// use inkwell::targets::{InitializationConfig, Target};
///
/// Target::initialize_native(&InitializationConfig::default()).expect("Failed to initialize native target");
///
/// let context = Context::get_global();
/// let module = Module::create("my_module");
/// let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
///
/// assert_eq!(execution_engine.get_module_at(0).get_context(), context);
/// ```
pub fn create_jit_execution_engine(self, opt_level: OptimizationLevel) -> Result<ExecutionEngine, String> {
let mut execution_engine = unsafe { uninitialized() };
let mut err_str = unsafe { zeroed() };

let code = unsafe {
LLVMCreateJITCompilerForModule(&mut execution_engine, self.module, opt_level, &mut err_str) // Should take ownership of module
LLVMCreateJITCompilerForModule(&mut execution_engine, self.module, opt_level as u32, &mut err_str) // Should take ownership of module
};

if code == 1 {
Expand All @@ -240,12 +307,12 @@ impl Module {
Ok(execution_engine)
}

pub fn add_global(&self, type_: &BasicType, address_space: Option<u32>, name: &str) -> GlobalValue {
pub fn add_global(&self, type_: &BasicType, address_space: Option<AddressSpace>, name: &str) -> GlobalValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

let value = unsafe {
match address_space {
Some(address_space) => LLVMAddGlobalInAddressSpace(self.module, type_.as_type_ref(), c_string.as_ptr(), address_space),
Some(address_space) => LLVMAddGlobalInAddressSpace(self.module, type_.as_type_ref(), c_string.as_ptr(), address_space as u32),
None => LLVMAddGlobal(self.module, type_.as_type_ref(), c_string.as_ptr()),
}
};
Expand Down Expand Up @@ -289,7 +356,17 @@ impl Module {
MemoryBuffer::new(memory_buffer)
}

/// Ensures that the current `Module` is valid, and returns a `bool`
/// that describes whether or not it is.
///
/// * `print` - Whether or not a message describing the error should be printed
/// to stderr, in case of failure.
///
/// # Remarks
/// See also: http://llvm.org/doxygen/Analysis_2Analysis_8cpp_source.html
pub fn verify(&self, print: bool) -> bool {
// REVIEW <6A>: Maybe, instead of printing the module to stderr with `print`,
// we should return Result<(), String> that contains an error string?
let mut err_str = unsafe { zeroed() };

let action = if print {
Expand Down Expand Up @@ -341,12 +418,14 @@ impl Module {
.set(self.get_raw_data_layout());
}

/// Prints the content of the `Module` to stderr.
pub fn print_to_stderr(&self) {
unsafe {
LLVMDumpModule(self.module);
}
}

/// Prints the content of the `Module` to a string.
pub fn print_to_string(&self) -> &CStr {
unsafe {
CStr::from_ptr(LLVMPrintModuleToString(self.module))
Expand Down
12 changes: 4 additions & 8 deletions src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use llvm_sys::transforms::pass_manager_builder::{LLVMPassManagerBuilderRef, LLVM
use llvm_sys::transforms::scalar::{LLVMAddAggressiveDCEPass, LLVMAddMemCpyOptPass, LLVMAddBitTrackingDCEPass, LLVMAddAlignmentFromAssumptionsPass, LLVMAddCFGSimplificationPass, LLVMAddDeadStoreEliminationPass, LLVMAddScalarizerPass, LLVMAddMergedLoadStoreMotionPass, LLVMAddGVNPass, LLVMAddIndVarSimplifyPass, LLVMAddInstructionCombiningPass, LLVMAddJumpThreadingPass, LLVMAddLICMPass, LLVMAddLoopDeletionPass, LLVMAddLoopIdiomPass, LLVMAddLoopRotatePass, LLVMAddLoopRerollPass, LLVMAddLoopUnrollPass, LLVMAddLoopUnswitchPass, LLVMAddPartiallyInlineLibCallsPass, LLVMAddLowerSwitchPass, LLVMAddPromoteMemoryToRegisterPass, LLVMAddSCCPPass, LLVMAddScalarReplAggregatesPass, LLVMAddScalarReplAggregatesPassSSA, LLVMAddScalarReplAggregatesPassWithThreshold, LLVMAddSimplifyLibCallsPass, LLVMAddTailCallEliminationPass, LLVMAddConstantPropagationPass, LLVMAddDemoteMemoryToRegisterPass, LLVMAddVerifierPass, LLVMAddCorrelatedValuePropagationPass, LLVMAddEarlyCSEPass, LLVMAddLowerExpectIntrinsicPass, LLVMAddTypeBasedAliasAnalysisPass, LLVMAddScopedNoAliasAAPass, LLVMAddBasicAliasAnalysisPass, LLVMAddReassociatePass};
use llvm_sys::transforms::vectorize::{LLVMAddBBVectorizePass, LLVMAddLoopVectorizePass, LLVMAddSLPVectorizePass};

use OptimizationLevel;
use module::Module;
use targets::{CodeGenOptLevel, TargetData};
use targets::TargetData;
use values::{AsValueRef, FunctionValue};

// REVIEW: Opt Level might be identical to targets::Option<CodeGenOptLevel>
Expand All @@ -34,14 +35,9 @@ impl PassManagerBuilder {
PassManagerBuilder::new(pass_manager_builder)
}

pub fn set_optimization_level(&self, opt_level: Option<&CodeGenOptLevel>) {
let opt_level = match opt_level {
Some(level) => level.as_u32(),
None => 0
};

pub fn set_optimization_level(&self, opt_level: OptimizationLevel) {
unsafe {
LLVMPassManagerBuilderSetOptLevel(self.pass_manager_builder, opt_level)
LLVMPassManagerBuilderSetOptLevel(self.pass_manager_builder, opt_level as u32)
}
}

Expand Down
28 changes: 6 additions & 22 deletions src/targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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 OptimizationLevel;
use context::Context;
use data_layout::DataLayout;
use passes::PassManager;
Expand All @@ -13,23 +14,6 @@ use std::ffi::{CStr, CString};
use std::mem::zeroed;
use std::ptr;

#[derive(Debug, PartialEq, Eq)]
pub enum CodeGenOptLevel {
Less,
Default,
Aggressive,
}

impl CodeGenOptLevel {
pub(crate) fn as_u32(&self) -> u32 {
match *self {
CodeGenOptLevel::Less => 1,
CodeGenOptLevel::Default => 2,
CodeGenOptLevel::Aggressive => 3,
}
}
}

#[derive(Debug, PartialEq, Eq)]
pub enum CodeModel {
Default,
Expand Down Expand Up @@ -541,15 +525,15 @@ impl Target {
}
}

pub fn create_target_machine(&self, triple: &str, cpu: &str, features: &str, level: Option<CodeGenOptLevel>, reloc_mode: RelocMode, code_model: CodeModel) -> Option<TargetMachine> {
pub fn create_target_machine(&self, triple: &str, cpu: &str, features: &str, level: OptimizationLevel, reloc_mode: RelocMode, code_model: CodeModel) -> Option<TargetMachine> {
let triple = CString::new(triple).expect("Conversion to CString failed unexpectedly");
let cpu = CString::new(cpu).expect("Conversion to CString failed unexpectedly");
let features = CString::new(features).expect("Conversion to CString failed unexpectedly");
let level = match level {
None => LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
Some(CodeGenOptLevel::Less) => LLVMCodeGenOptLevel::LLVMCodeGenLevelLess,
Some(CodeGenOptLevel::Default) => LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
Some(CodeGenOptLevel::Aggressive) => LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive,
OptimizationLevel::None => LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
OptimizationLevel::Less => LLVMCodeGenOptLevel::LLVMCodeGenLevelLess,
OptimizationLevel::Default => LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
OptimizationLevel::Aggressive => LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive,
};
let code_model = match code_model {
CodeModel::Default => LLVMCodeModel::LLVMCodeModelDefault,
Expand Down
9 changes: 5 additions & 4 deletions tests/test_builder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
extern crate inkwell;

use self::inkwell::OptimizationLevel;
use self::inkwell::context::Context;
use self::inkwell::builder::Builder;
use self::inkwell::targets::{InitializationConfig, Target};
Expand Down Expand Up @@ -42,7 +43,7 @@ fn test_null_checked_ptr_ops() {
let context = Context::create();
let module = context.create_module("unsafe");
let builder = context.create_builder();
let execution_engine = module.create_jit_execution_engine(0).unwrap();
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
let module = execution_engine.get_module_at(0);

// Here we're going to create a function that looks roughly like:
Expand Down Expand Up @@ -107,7 +108,7 @@ fn test_binary_ops() {
let context = Context::create();
let module = context.create_module("unsafe");
let builder = context.create_builder();
let execution_engine = module.create_jit_execution_engine(0).unwrap();
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
let module = execution_engine.get_module_at(0);

// Here we're going to create an and function which looks roughly like:
Expand Down Expand Up @@ -193,7 +194,7 @@ fn test_switch() {
let context = Context::create();
let module = context.create_module("unsafe");
let builder = context.create_builder();
let execution_engine = module.create_jit_execution_engine(0).unwrap();
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
let module = execution_engine.get_module_at(0);

// Here we're going to create a function which looks roughly like:
Expand Down Expand Up @@ -253,7 +254,7 @@ fn test_bit_shifts() {
let context = Context::create();
let module = context.create_module("unsafe");
let builder = context.create_builder();
let execution_engine = module.create_jit_execution_engine(0).unwrap();
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
let module = execution_engine.get_module_at(0);

// Here we're going to create a function which looks roughly like:
Expand Down
Loading

0 comments on commit 8c7dcf9

Please sign in to comment.