Skip to content

Commit

Permalink
auto merge of #6778 : Aatch/rust/pass-refactor, r=graydon
Browse files Browse the repository at this point in the history
Refactor the optimization passes to explicitly use the passes. This commit just re-implements the same passes as were already being run.

It also adds an option (behind `-Z`) to run the LLVM lint pass on the unoptimized IR.

This should close #2812. It is also the first step towards #2396

----------------

This is pretty much just an initial "get it out there" PR. With finer control over the optimization passes coming later. I also just blindly copied the passes we were already doing, so there could almost certainly be some more work in paring it down.

The other thing is the addition of the `mergefunctions` pass, which is currently enabled at `--opt-level=3` and does have a small impact on the code size. However the fact that it is at the end of the optimization pipeline is probably not ideal, so some more experimentation is in order.
  • Loading branch information
bors committed May 29, 2013
2 parents e0d6486 + 4ad0b8a commit e946b4f
Show file tree
Hide file tree
Showing 11 changed files with 719 additions and 100 deletions.
2 changes: 1 addition & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ DRIVER_CRATE := $(S)src/driver/driver.rs

# FIXME: x86-ism
LLVM_COMPONENTS=x86 arm mips ipo bitreader bitwriter linker asmparser jit mcjit \
interpreter
interpreter instrumentation

define DEF_LLVM_VARS
# The configure script defines these variables with the target triples
Expand Down
2 changes: 1 addition & 1 deletion mk/rustllvm.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ LLVM_EXTRA_INCDIRS_$(1)= -iquote $(S)src/llvm/include \
-iquote llvm/$(1)/include
endif

RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, RustWrapper.cpp)
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, RustWrapper.cpp PassWrapper.cpp)

RUSTLLVM_DEF_$(1) := rustllvm/rustllvm$(CFG_DEF_SUFFIX_$(1))

Expand Down
70 changes: 18 additions & 52 deletions src/librustc/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,11 @@ pub mod write {
use driver::session::Session;
use driver::session;
use lib::llvm::llvm;
use lib::llvm::{False, ModuleRef, mk_pass_manager, mk_target_data};
use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
use lib;

use back::passes;

use core::libc::{c_int, c_uint};
use core::path::Path;
use core::run;
Expand All @@ -202,16 +204,12 @@ pub mod write {
unsafe {
let opts = sess.opts;
if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
let mut pm = mk_pass_manager();
let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
let pm = mk_pass_manager();
llvm::LLVMAddTargetData(td.lltd, pm.llpm);
// FIXME (#2812): run the linter here also, once there are llvm-c
// bindings for it.

// Generate a pre-optimization intermediate file if -save-temps
// was specified.


if opts.save_temps {
match output_type {
output_type_bitcode => {
Expand All @@ -230,50 +228,22 @@ pub mod write {
}
}
}
if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
// FIXME (#2396): This is mostly a copy of the bits of opt's -O2
// that are available in the C api.
// Also: We might want to add optimization levels like -O1, -O2,
// -Os, etc
// Also: Should we expose and use the pass lists used by the opt
// tool?

if opts.optimize != session::No {
let fpm = mk_pass_manager();
llvm::LLVMAddTargetData(td.lltd, fpm.llpm);

let FPMB = llvm::LLVMPassManagerBuilderCreate();
llvm::LLVMPassManagerBuilderSetOptLevel(FPMB, 2u as c_uint);
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(
FPMB, fpm.llpm);
llvm::LLVMPassManagerBuilderDispose(FPMB);

llvm::LLVMRunPassManager(fpm.llpm, llmod);
let mut threshold = 225;
if opts.optimize == session::Aggressive { threshold = 275; }

let MPMB = llvm::LLVMPassManagerBuilderCreate();
llvm::LLVMPassManagerBuilderSetOptLevel(MPMB,
opts.optimize as
c_uint);
llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, False);
llvm::LLVMPassManagerBuilderSetDisableUnitAtATime(MPMB,
False);
llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(MPMB,
False);
llvm::LLVMPassManagerBuilderSetDisableSimplifyLibCalls(MPMB,
False);

if threshold != 0u {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold
(MPMB, threshold as c_uint);
}
llvm::LLVMPassManagerBuilderPopulateModulePassManager(
MPMB, pm.llpm);

llvm::LLVMPassManagerBuilderDispose(MPMB);
let mut mpm = passes::PassManager::new(td.lltd);

if !sess.no_verify() {
mpm.addPass(llvm::LLVMCreateVerifierPass());
}
if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }

if sess.lint_llvm() {
mpm.addPass(llvm::LLVMCreateLintPass());
}

passes::populatePassManager(&mut mpm, opts.optimize);

debug!("Running Module Optimization Pass");
mpm.run(llmod);

if is_object_or_assembly_or_exe(output_type) || opts.jit {
let LLVMOptNone = 0 as c_int; // -O0
let LLVMOptLess = 1 as c_int; // -O1
Expand Down Expand Up @@ -312,12 +282,9 @@ pub mod write {
// Always output the bitcode file with --save-temps

let filename = output.with_filetype("opt.bc");
llvm::LLVMRunPassManager(pm.llpm, llmod);
str::as_c_str(filename.to_str(), |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf)
});
pm = mk_pass_manager();

// Save the assembly file if -S is used
if output_type == output_type_assembly {
WriteOutputFile(
Expand Down Expand Up @@ -377,7 +344,6 @@ pub mod write {
} else {
// If only a bitcode file is asked for by using the
// '--emit-llvm' flag, then output it here
llvm::LLVMRunPassManager(pm.llpm, llmod);
str::as_c_str(output.to_str(),
|buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) );
}
Expand Down
154 changes: 154 additions & 0 deletions src/librustc/back/passes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use driver::session;
use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
use lib::llvm::llvm;
use lib;

pub struct PassManager {
priv llpm: PassManagerRef
}

impl Drop for PassManager {
fn finalize(&self) {
unsafe {
llvm::LLVMDisposePassManager(self.llpm);
}
}
}

impl PassManager {
pub fn new(td: TargetDataRef) -> PassManager {
unsafe {
let pm = PassManager {
llpm: llvm::LLVMCreatePassManager()
};
llvm::LLVMAddTargetData(td, pm.llpm);

return pm;
}
}

pub fn addPass(&mut self, pass:PassRef) {
unsafe {
llvm::LLVMAddPass(self.llpm, pass);
}
}

pub fn run(&self, md:ModuleRef) -> bool {
unsafe {
llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
}
}
}


pub fn populatePassManager(pm: &mut PassManager, level:session::OptLevel) {
unsafe {
// We add a lot of normally-unused prototypes, so always strip them
// straight away, later passes will get rid of any that are optimized
// away
pm.addPass(llvm::LLVMCreateStripDeadPrototypesPass());
if level == session::No {
pm.addPass(llvm::LLVMCreateAlwaysInlinerPass());

return;
}

//NOTE: Add library info

pm.addPass(llvm::LLVMCreateTypeBasedAliasAnalysisPass());
pm.addPass(llvm::LLVMCreateBasicAliasAnalysisPass());

pm.addPass(llvm::LLVMCreateSROAPass());
pm.addPass(llvm::LLVMCreateEarlyCSEPass());
pm.addPass(llvm::LLVMCreateLowerExpectIntrinsicPass());

pm.addPass(llvm::LLVMCreateGlobalOptimizerPass());
pm.addPass(llvm::LLVMCreateIPSCCPPass());
pm.addPass(llvm::LLVMCreateDeadArgEliminationPass());
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());

pm.addPass(llvm::LLVMCreatePruneEHPass());

if level == session::Aggressive {
// Do this before inlining, since inlining might
// make minor changes to functions that mean they
// can't be merged, despite being almost identical
pm.addPass(llvm::LLVMCreateMergeFunctionsPass());
}

match level {
session::Less => pm.addPass(llvm::LLVMCreateFunctionInliningPass(200)),
session::Default => pm.addPass(llvm::LLVMCreateFunctionInliningPass(225)),
session::Aggressive => pm.addPass(llvm::LLVMCreateFunctionInliningPass(275)),
session::No => ()
}

pm.addPass(llvm::LLVMCreateFunctionAttrsPass());

if level == session::Aggressive {
pm.addPass(llvm::LLVMCreateArgumentPromotionPass());
}

pm.addPass(llvm::LLVMCreateEarlyCSEPass());
pm.addPass(llvm::LLVMCreateSimplifyLibCallsPass());
pm.addPass(llvm::LLVMCreateJumpThreadingPass());
pm.addPass(llvm::LLVMCreateCorrelatedValuePropagationPass());
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());

pm.addPass(llvm::LLVMCreateTailCallEliminationPass());
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());
pm.addPass(llvm::LLVMCreateReassociatePass());
pm.addPass(llvm::LLVMCreateLoopRotatePass());
pm.addPass(llvm::LLVMCreateLICMPass());

pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
pm.addPass(llvm::LLVMCreateIndVarSimplifyPass());
pm.addPass(llvm::LLVMCreateLoopIdiomPass());
pm.addPass(llvm::LLVMCreateLoopDeletionPass());

if level == session::Aggressive {
pm.addPass(llvm::LLVMCreateLoopVectorizePass());
}
pm.addPass(llvm::LLVMCreateLoopUnrollPass());

if level != session::Less {
pm.addPass(llvm::LLVMCreateGVNPass());
}
pm.addPass(llvm::LLVMCreateMemCpyOptPass());
pm.addPass(llvm::LLVMCreateSCCPPass());

pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
pm.addPass(llvm::LLVMCreateJumpThreadingPass());
pm.addPass(llvm::LLVMCreateCorrelatedValuePropagationPass());
pm.addPass(llvm::LLVMCreateDeadStoreEliminationPass());

pm.addPass(llvm::LLVMCreateBBVectorizePass());
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
pm.addPass(llvm::LLVMCreateEarlyCSEPass());

pm.addPass(llvm::LLVMCreateLoopUnrollPass());

pm.addPass(llvm::LLVMCreateAggressiveDCEPass());
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());
pm.addPass(llvm::LLVMCreateInstructionSimplifierPass());

if level != session::Less {
pm.addPass(llvm::LLVMCreateGlobalDCEPass());
pm.addPass(llvm::LLVMCreateConstantMergePass());
}
}
}
5 changes: 5 additions & 0 deletions src/librustc/driver/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub static extra_debug_info: uint = 1 << 21;
pub static statik: uint = 1 << 22;
pub static print_link_args: uint = 1 << 23;
pub static no_debug_borrows: uint = 1 << 24;
pub static lint_llvm : uint = 1 << 25;

pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
~[(~"verbose", ~"in general, enable more debug printouts", verbose),
Expand Down Expand Up @@ -107,6 +108,9 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
(~"no-debug-borrows",
~"do not show where borrow checks fail",
no_debug_borrows),
(~"lint-llvm",
~"Run the LLVM lint pass on the pre-optimization IR",
lint_llvm),
]
}

Expand Down Expand Up @@ -265,6 +269,7 @@ pub impl Session_ {
fn meta_stats(@self) -> bool { self.debugging_opt(meta_stats) }
fn asm_comments(@self) -> bool { self.debugging_opt(asm_comments) }
fn no_verify(@self) -> bool { self.debugging_opt(no_verify) }
fn lint_llvm(@self) -> bool { self.debugging_opt(lint_llvm) }
fn trace(@self) -> bool { self.debugging_opt(trace) }
fn coherence(@self) -> bool { self.debugging_opt(coherence) }
fn borrowck_stats(@self) -> bool { self.debugging_opt(borrowck_stats) }
Expand Down
Loading

0 comments on commit e946b4f

Please sign in to comment.