2013-05-30 05:16:33 -05:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2013-05-27 18:15:31 -05:00
|
|
|
// 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.
|
|
|
|
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::str;
|
|
|
|
use std::io;
|
2013-05-27 18:15:31 -05:00
|
|
|
|
2013-05-30 05:16:33 -05:00
|
|
|
use driver::session::{OptLevel, No, Less, Aggressive};
|
2013-05-29 03:08:20 -05:00
|
|
|
use driver::session::{Session};
|
2013-05-28 00:55:16 -05:00
|
|
|
use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
|
2013-05-27 18:15:31 -05:00
|
|
|
use lib::llvm::llvm;
|
|
|
|
use lib;
|
|
|
|
|
|
|
|
pub struct PassManager {
|
|
|
|
priv llpm: PassManagerRef
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for PassManager {
|
2013-06-20 20:06:13 -05:00
|
|
|
fn drop(&self) {
|
2013-05-27 18:15:31 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
pub fn add_pass(&mut self, pass:PassRef) {
|
2013-05-27 18:15:31 -05:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMAddPass(self.llpm, pass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
pub fn add_pass_from_name(&mut self, name:&str) {
|
|
|
|
let pass = create_pass(name).unwrap();
|
|
|
|
self.add_pass(pass);
|
|
|
|
}
|
|
|
|
|
2013-05-27 18:15:31 -05:00
|
|
|
pub fn run(&self, md:ModuleRef) -> bool {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
|
|
|
|
let mut passes = ~[];
|
|
|
|
|
|
|
|
// mostly identical to clang 3.3, all differences are documented with comments
|
|
|
|
|
|
|
|
if level != No {
|
|
|
|
passes.push(~"targetlibinfo");
|
|
|
|
passes.push(~"no-aa");
|
|
|
|
// "tbaa" omitted, we don't emit clang-style type-based alias analysis information
|
|
|
|
passes.push(~"basicaa");
|
|
|
|
passes.push(~"globalopt");
|
|
|
|
passes.push(~"ipsccp");
|
|
|
|
passes.push(~"deadargelim");
|
|
|
|
passes.push(~"instcombine");
|
|
|
|
passes.push(~"simplifycfg");
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
2013-05-28 00:55:16 -05:00
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
passes.push(~"basiccg");
|
2013-05-27 18:15:31 -05:00
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
if level != No {
|
|
|
|
passes.push(~"prune-eh");
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
2013-05-27 18:15:31 -05:00
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
passes.push(~"inline-cost");
|
2013-05-29 03:08:20 -05:00
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
if level == No || level == Less {
|
|
|
|
passes.push(~"always-inline");
|
|
|
|
} else {
|
|
|
|
passes.push(~"inline");
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
if level != No {
|
|
|
|
passes.push(~"functionattrs");
|
|
|
|
if level == Aggressive {
|
|
|
|
passes.push(~"argpromotion");
|
|
|
|
}
|
|
|
|
passes.push(~"sroa");
|
|
|
|
passes.push(~"domtree");
|
|
|
|
passes.push(~"early-cse");
|
|
|
|
passes.push(~"simplify-libcalls");
|
|
|
|
passes.push(~"lazy-value-info");
|
|
|
|
passes.push(~"jump-threading");
|
|
|
|
passes.push(~"correlated-propagation");
|
|
|
|
passes.push(~"simplifycfg");
|
|
|
|
passes.push(~"instcombine");
|
|
|
|
passes.push(~"tailcallelim");
|
|
|
|
passes.push(~"simplifycfg");
|
|
|
|
passes.push(~"reassociate");
|
|
|
|
passes.push(~"domtree");
|
|
|
|
passes.push(~"loops");
|
|
|
|
passes.push(~"loop-simplify");
|
|
|
|
passes.push(~"lcssa");
|
|
|
|
passes.push(~"loop-rotate");
|
|
|
|
passes.push(~"licm");
|
|
|
|
passes.push(~"lcssa");
|
|
|
|
passes.push(~"loop-unswitch");
|
|
|
|
passes.push(~"instcombine");
|
|
|
|
passes.push(~"scalar-evolution");
|
|
|
|
passes.push(~"loop-simplify");
|
|
|
|
passes.push(~"lcssa");
|
|
|
|
passes.push(~"indvars");
|
|
|
|
passes.push(~"loop-idiom");
|
|
|
|
passes.push(~"loop-deletion");
|
|
|
|
if level == Aggressive {
|
|
|
|
passes.push(~"loop-simplify");
|
|
|
|
passes.push(~"lcssa");
|
|
|
|
passes.push(~"loop-vectorize");
|
|
|
|
passes.push(~"loop-simplify");
|
|
|
|
passes.push(~"lcssa");
|
|
|
|
passes.push(~"scalar-evolution");
|
|
|
|
passes.push(~"loop-simplify");
|
|
|
|
passes.push(~"lcssa");
|
|
|
|
}
|
|
|
|
if level != Less {
|
|
|
|
passes.push(~"loop-unroll");
|
|
|
|
passes.push(~"memdep");
|
|
|
|
passes.push(~"gvn");
|
|
|
|
}
|
|
|
|
passes.push(~"memdep");
|
|
|
|
passes.push(~"memcpyopt");
|
|
|
|
passes.push(~"sccp");
|
|
|
|
passes.push(~"instcombine");
|
|
|
|
passes.push(~"lazy-value-info");
|
|
|
|
passes.push(~"jump-threading");
|
|
|
|
passes.push(~"correlated-propagation");
|
|
|
|
passes.push(~"domtree");
|
|
|
|
passes.push(~"memdep");
|
|
|
|
passes.push(~"dse");
|
|
|
|
passes.push(~"adce");
|
|
|
|
passes.push(~"simplifycfg");
|
|
|
|
passes.push(~"instcombine");
|
|
|
|
// clang does `strip-dead-prototypes` here, since it does not emit them
|
|
|
|
}
|
2013-05-29 03:08:20 -05:00
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
// rustc emits dead prototypes, so always ask LLVM to strip them
|
|
|
|
passes.push(~"strip-dead-prototypes");
|
2013-05-27 18:15:31 -05:00
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
if level != Less {
|
|
|
|
passes.push(~"globaldce");
|
|
|
|
passes.push(~"constmerge");
|
|
|
|
}
|
|
|
|
|
2013-06-28 16:14:28 -05:00
|
|
|
passes
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
|
2013-06-21 07:29:53 -05:00
|
|
|
for pass_list.iter().advance |&nm| {
|
2013-05-29 03:08:20 -05:00
|
|
|
match create_pass(nm) {
|
|
|
|
Some(p) => pm.add_pass(p),
|
|
|
|
None => sess.warn(fmt!("Unknown pass %s", nm))
|
2013-05-27 18:15:31 -05:00
|
|
|
}
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-27 18:15:31 -05:00
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
pub fn create_pass(name:&str) -> Option<PassRef> {
|
|
|
|
do str::as_c_str(name) |s| {
|
|
|
|
unsafe {
|
|
|
|
let p = llvm::LLVMCreatePass(s);
|
|
|
|
if p.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(p)
|
|
|
|
}
|
2013-05-27 18:15:31 -05:00
|
|
|
}
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-27 18:15:31 -05:00
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
pub fn list_passes() {
|
|
|
|
io::println("\nAvailable Passes:");
|
2013-05-27 18:15:31 -05:00
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
io::println("\nAnalysis Passes:");
|
2013-06-21 07:29:53 -05:00
|
|
|
for analysis_passes.iter().advance |&(name, desc)| {
|
2013-05-29 03:08:20 -05:00
|
|
|
io::println(fmt!(" %-30s -- %s", name, desc));
|
|
|
|
}
|
|
|
|
io::println("\nTransformation Passes:");
|
2013-06-21 07:29:53 -05:00
|
|
|
for transform_passes.iter().advance |&(name, desc)| {
|
2013-05-29 03:08:20 -05:00
|
|
|
io::println(fmt!(" %-30s -- %s", name, desc));
|
|
|
|
}
|
|
|
|
io::println("\nUtility Passes:");
|
2013-06-21 07:29:53 -05:00
|
|
|
for utility_passes.iter().advance |&(name, desc)| {
|
2013-05-29 03:08:20 -05:00
|
|
|
io::println(fmt!(" %-30s -- %s", name, desc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Analysis Passes */
|
|
|
|
pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
|
|
|
|
("aa-eval", "Exhausive Alias Analysis Precision Evaluator"),
|
|
|
|
("asan", "AddressSanitizer"),
|
|
|
|
("basicaa", "Basic Alias Analysis"),
|
|
|
|
("basiccg", "Basic CallGraph Construction"),
|
|
|
|
("block-freq", "Block Frequency Analysis"),
|
|
|
|
("cost-model", "Cost Model Analysis"),
|
|
|
|
("count-aa", "Count Alias Analysis Query Responses"),
|
|
|
|
("da", "Dependence Analysis"),
|
|
|
|
("debug-aa", "AA Use Debugger"),
|
|
|
|
("domfrontier", "Dominance Frontier Construction"),
|
|
|
|
("domtree", "Dominator Tree Construction"),
|
|
|
|
("globalsmodref-aa", "Simple mod/ref analysis for globals"),
|
|
|
|
("instcount", "Count the various types of Instructions"),
|
|
|
|
("intervals", "Interval Partition Construction"),
|
|
|
|
("iv-users", "Induction Variable Users"),
|
|
|
|
("lazy-value-info", "Lazy Value Information Analysis"),
|
|
|
|
("libcall-aa", "LibCall Alias Analysis"),
|
|
|
|
("lint", "Statically lint-check LLVM IR"),
|
|
|
|
("loops", "Natural Loop Information"),
|
|
|
|
("memdep", "Memory Dependence Analysis"),
|
|
|
|
("module-debuginfo", "Decodes module-level debug info"),
|
|
|
|
("profile-estimator", "Estimate profiling information"),
|
|
|
|
("profile-loader", "Load profile information from llvmprof.out"),
|
|
|
|
("profile-verifier", "Verify profiling information"),
|
|
|
|
("regions", "Detect single entry single exit regions"),
|
|
|
|
("scalar-evolution", "Scalar Evolution Analysis"),
|
|
|
|
("scev-aa", "Scalar Evolution-based Alias Analysis"),
|
|
|
|
("tbaa", "Type-Based Alias Analysis"),
|
|
|
|
("tsan", "ThreadSanitizer"),
|
|
|
|
];
|
2013-05-28 20:12:36 -05:00
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
/** Transformation Passes */
|
|
|
|
pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
|
|
|
|
("adce", "Aggressive Dead Code Elimination"),
|
2013-06-18 16:45:18 -05:00
|
|
|
("always-inline", "Inliner for #[inline] functions"),
|
2013-05-29 03:08:20 -05:00
|
|
|
("argpromotion", "Promote 'by reference' arguments to scalars"),
|
|
|
|
("bb-vectorize", "Basic-Block Vectorization"),
|
|
|
|
("block-placement", "Profile Guided Basic Block Placement"),
|
|
|
|
("bounds-checking", "Run-time bounds checking"),
|
|
|
|
("break-crit-edges", "Break critical edges in CFG"),
|
|
|
|
("codegenprepare", "Optimize for code generation"),
|
|
|
|
("constmerge", "Merge Duplicate Global Constants"),
|
|
|
|
("constprop", "Simple constant propagation"),
|
|
|
|
("correlated-propagation", "Value Propagation"),
|
|
|
|
("da", "Data Layout"),
|
|
|
|
("dce", "Dead Code Elimination"),
|
|
|
|
("deadargelim", "Dead Argument Elimination"),
|
|
|
|
("die", "Dead Instruction Elimination"),
|
|
|
|
("dse", "Dead Store Elimination"),
|
|
|
|
("early-cse", "Early CSE"),
|
|
|
|
("functionattrs", "Deduce function attributes"),
|
|
|
|
("globaldce", "Dead Global Elimination"),
|
|
|
|
("globalopt", "Global Variable Optimizer"),
|
|
|
|
("gvn", "Global Value Numbering"),
|
|
|
|
("indvars", "Canonicalize Induction Variables"),
|
|
|
|
("inline", "Function Integration/Inlining"),
|
|
|
|
("insert-edge-profiling", "Insert instrumentation for edge profiling"),
|
|
|
|
("insert-gcov-profiling", "Insert instrumentation for GCOV profiling"),
|
|
|
|
("insert-optimal-edge-profiling", "Insert optimal instrumentation for edge profiling"),
|
|
|
|
("instcombine", "Combine redundant instructions"),
|
|
|
|
("instsimplify", "Remove redundant instructions"),
|
|
|
|
("ipconstprop", "Interprocedural constant propagation"),
|
|
|
|
("ipsccp", "Interprocedural Sparse Conditional Constant Propagation"),
|
|
|
|
("jump-threading", "Jump Threading"),
|
|
|
|
("lcssa", "Loop-Closed SSA Form Pass"),
|
|
|
|
("licm", "Loop Invariant Code Motion"),
|
|
|
|
("loop-deletion", "Delete dead loops"),
|
|
|
|
("loop-extract", "Extract loops into new functions"),
|
|
|
|
("loop-extract-single", "Extract at most one loop into a new function"),
|
|
|
|
("loop-idiom", "Recognise loop idioms"),
|
|
|
|
("loop-instsimplify", "Simplify instructions in loops"),
|
|
|
|
("loop-reduce", "Loop Strength Reduction"),
|
|
|
|
("loop-rotate", "Rotate Loops"),
|
|
|
|
("loop-simplify", "Canonicalize natural loops"),
|
|
|
|
("loop-unroll", "Unroll loops"),
|
|
|
|
("loop-unswitch", "Unswitch loops"),
|
|
|
|
("loop-vectorize", "Loop Vectorization"),
|
|
|
|
("lower-expect", "Lower 'expect' Intrinsics"),
|
|
|
|
("mem2reg", "Promote Memory to Register"),
|
|
|
|
("memcpyopt", "MemCpy Optimization"),
|
|
|
|
("mergefunc", "Merge Functions"),
|
|
|
|
("mergereturn", "Unify function exit nodes"),
|
|
|
|
("partial-inliner", "Partial Inliner"),
|
|
|
|
("prune-eh", "Remove unused exception handling info"),
|
|
|
|
("reassociate", "Reassociate expressions"),
|
|
|
|
("reg2mem", "Demote all values to stack slots"),
|
|
|
|
("scalarrepl", "Scalar Replacement of Aggregates (DT)"),
|
|
|
|
("scalarrepl-ssa", "Scalar Replacement of Aggregates (SSAUp)"),
|
|
|
|
("sccp", "Sparse Conditional Constant Propagation"),
|
|
|
|
("simplify-libcalls", "Simplify well-known library calls"),
|
|
|
|
("simplifycfg", "Simplify the CFG"),
|
|
|
|
("sink", "Code sinking"),
|
|
|
|
("strip", "Strip all symbols from a module"),
|
|
|
|
("strip-dead-debug-info", "Strip debug info for unused symbols"),
|
|
|
|
("strip-dead-prototypes", "Strip Unused Function Prototypes"),
|
|
|
|
("strip-debug-declare", "Strip all llvm.dbg.declare intrinsics"),
|
|
|
|
("strip-nondebug", "Strip all symbols, except dbg symbols, from a module"),
|
|
|
|
("sroa", "Scalar Replacement of Aggregates"),
|
|
|
|
("tailcallelim", "Tail Call Elimination"),
|
|
|
|
];
|
2013-05-28 20:12:36 -05:00
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
/** Utility Passes */
|
|
|
|
static utility_passes : &'static [(&'static str, &'static str)] = &'static [
|
|
|
|
("instnamer", "Assign names to anonymous instructions"),
|
|
|
|
("verify", "Module Verifier"),
|
|
|
|
];
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn passes_exist() {
|
|
|
|
let mut failed = ~[];
|
|
|
|
unsafe { llvm::LLVMInitializePasses(); }
|
2013-06-21 07:29:53 -05:00
|
|
|
for analysis_passes.iter().advance |&(name,_)| {
|
2013-06-19 17:18:25 -05:00
|
|
|
let pass = create_pass(name);
|
|
|
|
if !pass.is_some() {
|
2013-05-29 03:08:20 -05:00
|
|
|
failed.push(name);
|
2013-06-19 17:18:25 -05:00
|
|
|
} else {
|
|
|
|
unsafe { llvm::LLVMDestroyPass(pass.get()) }
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
|
|
|
}
|
2013-06-21 07:29:53 -05:00
|
|
|
for transform_passes.iter().advance |&(name,_)| {
|
2013-06-19 17:18:25 -05:00
|
|
|
let pass = create_pass(name);
|
|
|
|
if !pass.is_some() {
|
2013-05-29 03:08:20 -05:00
|
|
|
failed.push(name);
|
2013-06-19 17:18:25 -05:00
|
|
|
} else {
|
|
|
|
unsafe { llvm::LLVMDestroyPass(pass.get()) }
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
|
|
|
}
|
2013-06-21 07:29:53 -05:00
|
|
|
for utility_passes.iter().advance |&(name,_)| {
|
2013-06-19 17:18:25 -05:00
|
|
|
let pass = create_pass(name);
|
|
|
|
if !pass.is_some() {
|
2013-05-29 03:08:20 -05:00
|
|
|
failed.push(name);
|
2013-06-19 17:18:25 -05:00
|
|
|
} else {
|
|
|
|
unsafe { llvm::LLVMDestroyPass(pass.get()) }
|
2013-05-29 03:08:20 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-28 20:12:36 -05:00
|
|
|
|
2013-05-29 03:08:20 -05:00
|
|
|
if failed.len() > 0 {
|
|
|
|
io::println("Some passes don't exist:");
|
2013-06-21 07:29:53 -05:00
|
|
|
for failed.iter().advance |&n| {
|
2013-05-29 03:08:20 -05:00
|
|
|
io::println(fmt!(" %s", n));
|
2013-05-27 18:15:31 -05:00
|
|
|
}
|
2013-05-29 03:08:20 -05:00
|
|
|
fail!();
|
2013-05-27 18:15:31 -05:00
|
|
|
}
|
|
|
|
}
|