Skip to content

Commit

Permalink
Added PassManagerBuilder
Browse files Browse the repository at this point in the history
Added test which calls all passes
Added test which creates pass manager builder and sets values
  • Loading branch information
TheDan64 committed Aug 25, 2017
1 parent 1ffb40d commit bfa5a2f
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 13 deletions.
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ pub fn enable_llvm_pretty_stack_trace() {
}
}

// TODO: Move
pub fn is_multithreaded() -> bool {
use llvm_sys::core::LLVMIsMultithreaded;

unsafe {
LLVMIsMultithreaded() == 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
8 changes: 0 additions & 8 deletions src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,6 @@ impl Module {
Ok(execution_engine)
}

pub fn create_function_pass_manager(&self) -> PassManager {
let pass_manager = unsafe {
LLVMCreateFunctionPassManagerForModule(self.module)
};

PassManager::new(pass_manager)
}

// REVIEW: Is this really always a pointer? It would make sense...
pub fn add_global(&self, type_: &BasicType, initial_value: Option<&BasicValue>, address_space: Option<u32>, name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
Expand Down
144 changes: 139 additions & 5 deletions src/pass_manager.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,111 @@
use llvm_sys::core::{LLVMDisposePassManager, LLVMInitializeFunctionPassManager};
use llvm_sys::core::{LLVMDisposePassManager, LLVMInitializeFunctionPassManager, LLVMFinalizeFunctionPassManager, LLVMRunFunctionPassManager, LLVMRunPassManager, LLVMCreatePassManager, LLVMCreateFunctionPassManagerForModule};
use llvm_sys::prelude::LLVMPassManagerRef;
use llvm_sys::target::LLVMAddTargetData;
use llvm_sys::transforms::ipo::{LLVMAddArgumentPromotionPass, LLVMAddConstantMergePass, LLVMAddDeadArgEliminationPass, LLVMAddFunctionAttrsPass, LLVMAddFunctionInliningPass, LLVMAddAlwaysInlinerPass, LLVMAddGlobalDCEPass, LLVMAddGlobalOptimizerPass, LLVMAddIPConstantPropagationPass, LLVMAddIPSCCPPass, LLVMAddInternalizePass, LLVMAddStripDeadPrototypesPass, LLVMAddPruneEHPass, LLVMAddStripSymbolsPass};
use llvm_sys::transforms::pass_manager_builder::{LLVMPassManagerBuilderRef, LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderDispose, LLVMPassManagerBuilderSetOptLevel, LLVMPassManagerBuilderSetSizeLevel, LLVMPassManagerBuilderSetDisableUnitAtATime, LLVMPassManagerBuilderSetDisableUnrollLoops, LLVMPassManagerBuilderSetDisableSimplifyLibCalls, LLVMPassManagerBuilderUseInlinerWithThreshold, LLVMPassManagerBuilderPopulateFunctionPassManager, LLVMPassManagerBuilderPopulateModulePassManager, LLVMPassManagerBuilderPopulateLTOPassManager};
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 targets::TargetData;
use module::Module;
use targets::{CodeGenOptLevel, TargetData};
use values::{AsValueRef, FunctionValue};

// REVIEW: Could possbily use the builder pattern for setting which passes to use
// REVIEW: Opt Level might be identical to targets::Option<CodeGenOptLevel>
// REVIEW: size_level 0-2 according to llvmlite
pub struct PassManagerBuilder {
pass_manager_builder: LLVMPassManagerBuilderRef,
}

impl PassManagerBuilder {
fn new(pass_manager_builder: LLVMPassManagerBuilderRef) -> Self {
assert!(!pass_manager_builder.is_null());

PassManagerBuilder {
pass_manager_builder: pass_manager_builder,
}
}

pub fn create() -> Self {
let pass_manager_builder = unsafe {
LLVMPassManagerBuilderCreate()
};

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
};

unsafe {
LLVMPassManagerBuilderSetOptLevel(self.pass_manager_builder, opt_level)
}
}

// REVIEW: Valid input 0-2 according to llvmlite
pub fn set_size_level(&self, size_level: u32) {
unsafe {
LLVMPassManagerBuilderSetSizeLevel(self.pass_manager_builder, size_level)
}
}

pub fn set_disable_unit_at_a_time(&self, disable: bool) {
unsafe {
LLVMPassManagerBuilderSetDisableUnitAtATime(self.pass_manager_builder, disable as i32)
}
}

pub fn set_disable_unroll_loops(&self, disable: bool) {
unsafe {
LLVMPassManagerBuilderSetDisableUnrollLoops(self.pass_manager_builder, disable as i32)
}
}

pub fn set_disable_simplify_lib_calls(&self, disable: bool) {
unsafe {
LLVMPassManagerBuilderSetDisableSimplifyLibCalls(self.pass_manager_builder, disable as i32)
}
}

pub fn set_inliner_with_threshold(&self, threshold: u32) {
unsafe {
LLVMPassManagerBuilderUseInlinerWithThreshold(self.pass_manager_builder, threshold)
}
}

// SubType: pass_manager: &PassManager<FunctionValue>
pub fn populate_function_pass_manager(&self, pass_manager: &PassManager) {
unsafe {
LLVMPassManagerBuilderPopulateFunctionPassManager(self.pass_manager_builder, pass_manager.pass_manager)
}
}

// SubType: pass_manager: &PassManager<Module>
pub fn populate_module_pass_manager(&self, pass_manager: &PassManager) {
unsafe {
LLVMPassManagerBuilderPopulateModulePassManager(self.pass_manager_builder, pass_manager.pass_manager)
}
}

// SubType: Need LTO subtype?
pub fn populate_lto_pass_manager(&self, pass_manager: &PassManager, internalize: bool, run_inliner: bool) {
unsafe {
LLVMPassManagerBuilderPopulateLTOPassManager(self.pass_manager_builder, pass_manager.pass_manager, internalize as i32, run_inliner as i32)
}
}
}

impl Drop for PassManagerBuilder {
fn drop(&mut self) {
unsafe {
LLVMPassManagerBuilderDispose(self.pass_manager_builder)
}
}
}

// SubTypes: PassManager<Module>, PassManager<FunctionValue>
pub struct PassManager {
pub(crate) pass_manager: LLVMPassManagerRef,
}
Expand All @@ -21,14 +119,50 @@ impl PassManager {
}
}

// SubTypes: PassManager<Module>::create()
pub fn create_for_module() -> Self {
let pass_manager = unsafe {
LLVMCreatePassManager()
};

PassManager::new(pass_manager)
}

// SubTypes: PassManager<FunctionValue>::create()
pub fn create_for_function(module: &Module) -> Self {
let pass_manager = unsafe {
LLVMCreateFunctionPassManagerForModule(module.module)
};

PassManager::new(pass_manager)
}

// return true means some pass modified the module, not an error occurred
pub fn initialize(&self) -> bool {
unsafe {
LLVMInitializeFunctionPassManager(self.pass_manager) == 1
}
}

pub fn add_target_data(&self, target_data: TargetData) {
pub fn finalize(&self) -> bool {
unsafe {
LLVMFinalizeFunctionPassManager(self.pass_manager) == 1
}
}

pub fn run_on_function(&self, fn_value: &FunctionValue) -> bool {
unsafe {
LLVMRunFunctionPassManager(self.pass_manager, fn_value.as_value_ref()) == 1
}
}

pub fn run_on_module(&self, module: &Module) -> bool {
unsafe {
LLVMRunPassManager(self.pass_manager, module.module) == 1
}
}

pub fn add_target_data(&self, target_data: &TargetData) {
unsafe {
LLVMAddTargetData(target_data.target_data, self.pass_manager)
}
Expand Down Expand Up @@ -131,7 +265,6 @@ impl PassManager {
}
}

// REVIEW: If slp stands for sleep, we should spell it out in full
pub fn add_slp_vectorize_pass(&self) {
unsafe {
LLVMAddSLPVectorizePass(self.pass_manager)
Expand Down Expand Up @@ -217,6 +350,7 @@ impl PassManager {
LLVMAddLICMPass(self.pass_manager)
}
}

pub fn add_loop_deletion_pass(&self) {
unsafe {
LLVMAddLoopDeletionPass(self.pass_manager)
Expand Down
10 changes: 10 additions & 0 deletions src/targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ pub enum CodeGenOptLevel {
Aggressive,
}

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

#[derive(Debug, PartialEq, Eq)]
pub enum CodeModel {
Default,
Expand Down
92 changes: 92 additions & 0 deletions tests/test_pass_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
extern crate inkwell;

use self::inkwell::context::Context;
use self::inkwell::pass_manager::{PassManagerBuilder, PassManager};
use self::inkwell::targets::CodeGenOptLevel::Aggressive;

#[test]
fn test_init_all_passes_for_module() {
let context = Context::create();
let module = context.create_module("my_module");
let pass_manager = PassManager::create_for_module();

pass_manager.add_argument_promotion_pass();
pass_manager.add_constant_merge_pass();
pass_manager.add_dead_arg_elimination_pass();
pass_manager.add_function_attrs_pass();
pass_manager.add_function_inlining_pass();
pass_manager.add_always_inliner_pass();
pass_manager.add_global_dce_pass();
pass_manager.add_global_optimizer_pass();
pass_manager.add_ip_constant_propagation_pass();
pass_manager.add_prune_eh_pass();
pass_manager.add_ipsccp_pass();
pass_manager.add_interinalize_pass(1);
pass_manager.add_strip_dead_prototypes_pass();
pass_manager.add_strip_symbol_pass();
pass_manager.add_bb_vectorize_pass();
pass_manager.add_loop_vectorize_pass();
pass_manager.add_slp_vectorize_pass();
pass_manager.add_aggressive_dce_pass();
pass_manager.add_bit_tracking_dce_pass(); // TODO: 3.7+ only
pass_manager.add_alignment_from_assumptions_pass();
pass_manager.add_cfg_simplification_pass();
pass_manager.add_dead_store_elimination_pass();
pass_manager.add_scalarizer_pass();
pass_manager.add_merged_load_store_motion_pass();
pass_manager.add_gvn_pass();
pass_manager.add_ind_var_simplify_pass();
pass_manager.add_instruction_combining_pass();
pass_manager.add_jump_threading_pass();
pass_manager.add_licm_pass();
pass_manager.add_loop_deletion_pass();
pass_manager.add_loop_idiom_pass();
pass_manager.add_loop_rotate_pass();
pass_manager.add_loop_reroll_pass();
pass_manager.add_loop_unroll_pass();
pass_manager.add_loop_unswitch_pass();
pass_manager.add_memcpy_optimize_pass();
pass_manager.add_partially_inline_lib_calls_pass();
pass_manager.add_lower_switch_pass();
pass_manager.add_promote_memory_to_register_pass();
pass_manager.add_reassociate_pass();
pass_manager.add_sccp_pass();
pass_manager.add_scalar_repl_aggregates_pass();
pass_manager.add_scalar_repl_aggregates_pass_ssa();
pass_manager.add_scalar_repl_aggregates_pass_with_threshold(1);
pass_manager.add_simplify_lib_calls_pass();
pass_manager.add_tail_call_elimination_pass();
pass_manager.add_constant_propagation_pass();
pass_manager.add_demote_memory_to_register_pass();
pass_manager.add_verifier_pass();
pass_manager.add_correlated_value_propagation_pass();
pass_manager.add_early_cse_pass();
pass_manager.add_lower_expect_intrinsic_pass();
pass_manager.add_type_based_alias_analysis_pass();
pass_manager.add_scoped_no_alias_aa_pass();
pass_manager.add_basic_alias_analysis_pass();

assert!(!pass_manager.initialize());
assert!(!pass_manager.finalize());

pass_manager.run_on_module(&module);

assert!(!pass_manager.initialize());
assert!(!pass_manager.finalize());

// TODO: Test when initialize and finalize are true
}

#[test]
fn test_pass_manager_builder() {
let builder = PassManagerBuilder::create();

builder.set_optimization_level(Some(&Aggressive));
builder.set_size_level(2);
builder.set_inliner_with_threshold(42);
builder.set_disable_unit_at_a_time(true);
builder.set_disable_unroll_loops(true);
builder.set_disable_simplify_lib_calls(true);

// TODO: Run on various type of pass managers
}
1 change: 1 addition & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod test_builder;
mod test_context;
mod test_execution_engine;
mod test_module;
mod test_pass_manager;
mod test_tari_example;
mod test_targets;
mod test_types;
Expand Down

0 comments on commit bfa5a2f

Please sign in to comment.