1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use std::c_str::ToCStr;
14 use driver::session::{OptLevel, No, Less, Aggressive};
15 use driver::session::{Session};
16 use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
20 pub struct PassManager {
21 priv llpm: PassManagerRef
24 impl Drop for PassManager {
27 llvm::LLVMDisposePassManager(self.llpm);
33 pub fn new(td: TargetDataRef) -> PassManager {
35 let pm = PassManager {
36 llpm: llvm::LLVMCreatePassManager()
38 llvm::LLVMAddTargetData(td, pm.llpm);
44 pub fn add_pass(&mut self, pass:PassRef) {
46 llvm::LLVMAddPass(self.llpm, pass);
50 pub fn add_pass_from_name(&mut self, name:&str) {
51 let pass = create_pass(name).unwrap();
55 pub fn run(&self, md:ModuleRef) -> bool {
57 llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
62 pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
65 // mostly identical to clang 3.3, all differences are documented with comments
68 passes.push(~"targetlibinfo");
69 passes.push(~"no-aa");
70 // "tbaa" omitted, we don't emit clang-style type-based alias analysis information
71 passes.push(~"basicaa");
72 passes.push(~"globalopt");
73 passes.push(~"ipsccp");
74 passes.push(~"deadargelim");
75 passes.push(~"instcombine");
76 passes.push(~"simplifycfg");
79 passes.push(~"basiccg");
82 passes.push(~"prune-eh");
85 passes.push(~"inline-cost");
87 if level == No || level == Less {
88 passes.push(~"always-inline");
90 passes.push(~"inline");
94 passes.push(~"functionattrs");
95 if level == Aggressive {
96 passes.push(~"argpromotion");
99 passes.push(~"domtree");
100 passes.push(~"early-cse");
101 passes.push(~"lazy-value-info");
102 passes.push(~"jump-threading");
103 passes.push(~"correlated-propagation");
104 passes.push(~"simplifycfg");
105 passes.push(~"instcombine");
106 passes.push(~"tailcallelim");
107 passes.push(~"simplifycfg");
108 passes.push(~"reassociate");
109 passes.push(~"domtree");
110 passes.push(~"loops");
111 passes.push(~"loop-simplify");
112 passes.push(~"lcssa");
113 passes.push(~"loop-rotate");
114 passes.push(~"licm");
115 passes.push(~"lcssa");
116 passes.push(~"loop-unswitch");
117 passes.push(~"instcombine");
118 passes.push(~"scalar-evolution");
119 passes.push(~"loop-simplify");
120 passes.push(~"lcssa");
121 passes.push(~"indvars");
122 passes.push(~"loop-idiom");
123 passes.push(~"loop-deletion");
124 if level == Aggressive {
125 passes.push(~"loop-simplify");
126 passes.push(~"lcssa");
127 passes.push(~"loop-vectorize");
128 passes.push(~"loop-simplify");
129 passes.push(~"lcssa");
130 passes.push(~"scalar-evolution");
131 passes.push(~"loop-simplify");
132 passes.push(~"lcssa");
135 passes.push(~"loop-unroll");
136 passes.push(~"memdep");
139 passes.push(~"memdep");
140 passes.push(~"memcpyopt");
141 passes.push(~"sccp");
142 passes.push(~"instcombine");
143 passes.push(~"lazy-value-info");
144 passes.push(~"jump-threading");
145 passes.push(~"correlated-propagation");
146 passes.push(~"domtree");
147 passes.push(~"memdep");
149 passes.push(~"adce");
150 passes.push(~"simplifycfg");
151 passes.push(~"instcombine");
152 // clang does `strip-dead-prototypes` here, since it does not emit them
155 // rustc emits dead prototypes, so always ask LLVM to strip them
156 passes.push(~"strip-dead-prototypes");
159 passes.push(~"globaldce");
160 passes.push(~"constmerge");
166 pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
167 for nm in pass_list.iter() {
168 match create_pass(*nm) {
169 Some(p) => pm.add_pass(p),
170 None => sess.warn(fmt!("Unknown pass %s", *nm))
175 pub fn create_pass(name:&str) -> Option<PassRef> {
176 do name.with_c_str |s| {
178 let p = llvm::LLVMCreatePass(s);
188 pub fn list_passes() {
189 io::println("\nAvailable Passes:");
191 io::println("\nAnalysis Passes:");
192 for &(name, desc) in analysis_passes.iter() {
193 printfln!(" %-30s -- %s", name, desc);
195 io::println("\nTransformation Passes:");
196 for &(name, desc) in transform_passes.iter() {
197 printfln!(" %-30s -- %s", name, desc);
199 io::println("\nUtility Passes:");
200 for &(name, desc) in utility_passes.iter() {
201 printfln!(" %-30s -- %s", name, desc);
205 /** Analysis Passes */
206 pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
207 ("aa-eval", "Exhausive Alias Analysis Precision Evaluator"),
208 ("asan", "AddressSanitizer"),
209 ("basicaa", "Basic Alias Analysis"),
210 ("basiccg", "Basic CallGraph Construction"),
211 ("block-freq", "Block Frequency Analysis"),
212 ("cost-model", "Cost Model Analysis"),
213 ("count-aa", "Count Alias Analysis Query Responses"),
214 ("da", "Dependence Analysis"),
215 ("debug-aa", "AA Use Debugger"),
216 ("domfrontier", "Dominance Frontier Construction"),
217 ("domtree", "Dominator Tree Construction"),
218 ("globalsmodref-aa", "Simple mod/ref analysis for globals"),
219 ("instcount", "Count the various types of Instructions"),
220 ("intervals", "Interval Partition Construction"),
221 ("iv-users", "Induction Variable Users"),
222 ("lazy-value-info", "Lazy Value Information Analysis"),
223 ("libcall-aa", "LibCall Alias Analysis"),
224 ("lint", "Statically lint-check LLVM IR"),
225 ("loops", "Natural Loop Information"),
226 ("memdep", "Memory Dependence Analysis"),
227 ("module-debuginfo", "Decodes module-level debug info"),
228 ("profile-estimator", "Estimate profiling information"),
229 ("profile-loader", "Load profile information from llvmprof.out"),
230 ("profile-verifier", "Verify profiling information"),
231 ("regions", "Detect single entry single exit regions"),
232 ("scalar-evolution", "Scalar Evolution Analysis"),
233 ("scev-aa", "Scalar Evolution-based Alias Analysis"),
234 ("tbaa", "Type-Based Alias Analysis"),
235 ("tsan", "ThreadSanitizer"),
238 /** Transformation Passes */
239 pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
240 ("adce", "Aggressive Dead Code Elimination"),
241 ("always-inline", "Inliner for #[inline] functions"),
242 ("argpromotion", "Promote 'by reference' arguments to scalars"),
243 ("bb-vectorize", "Basic-Block Vectorization"),
244 ("block-placement", "Profile Guided Basic Block Placement"),
245 ("bounds-checking", "Run-time bounds checking"),
246 ("break-crit-edges", "Break critical edges in CFG"),
247 ("codegenprepare", "Optimize for code generation"),
248 ("constmerge", "Merge Duplicate Global Constants"),
249 ("constprop", "Simple constant propagation"),
250 ("correlated-propagation", "Value Propagation"),
251 ("da", "Data Layout"),
252 ("dce", "Dead Code Elimination"),
253 ("deadargelim", "Dead Argument Elimination"),
254 ("die", "Dead Instruction Elimination"),
255 ("dse", "Dead Store Elimination"),
256 ("early-cse", "Early CSE"),
257 ("functionattrs", "Deduce function attributes"),
258 ("globaldce", "Dead Global Elimination"),
259 ("globalopt", "Global Variable Optimizer"),
260 ("gvn", "Global Value Numbering"),
261 ("indvars", "Canonicalize Induction Variables"),
262 ("inline", "Function Integration/Inlining"),
263 ("insert-edge-profiling", "Insert instrumentation for edge profiling"),
264 ("insert-gcov-profiling", "Insert instrumentation for GCOV profiling"),
265 ("insert-optimal-edge-profiling", "Insert optimal instrumentation for edge profiling"),
266 ("instcombine", "Combine redundant instructions"),
267 ("instsimplify", "Remove redundant instructions"),
268 ("ipconstprop", "Interprocedural constant propagation"),
269 ("ipsccp", "Interprocedural Sparse Conditional Constant Propagation"),
270 ("jump-threading", "Jump Threading"),
271 ("lcssa", "Loop-Closed SSA Form Pass"),
272 ("licm", "Loop Invariant Code Motion"),
273 ("loop-deletion", "Delete dead loops"),
274 ("loop-extract", "Extract loops into new functions"),
275 ("loop-extract-single", "Extract at most one loop into a new function"),
276 ("loop-idiom", "Recognise loop idioms"),
277 ("loop-instsimplify", "Simplify instructions in loops"),
278 ("loop-reduce", "Loop Strength Reduction"),
279 ("loop-rotate", "Rotate Loops"),
280 ("loop-simplify", "Canonicalize natural loops"),
281 ("loop-unroll", "Unroll loops"),
282 ("loop-unswitch", "Unswitch loops"),
283 ("loop-vectorize", "Loop Vectorization"),
284 ("lower-expect", "Lower 'expect' Intrinsics"),
285 ("mem2reg", "Promote Memory to Register"),
286 ("memcpyopt", "MemCpy Optimization"),
287 ("mergefunc", "Merge Functions"),
288 ("mergereturn", "Unify function exit nodes"),
289 ("partial-inliner", "Partial Inliner"),
290 ("prune-eh", "Remove unused exception handling info"),
291 ("reassociate", "Reassociate expressions"),
292 ("reg2mem", "Demote all values to stack slots"),
293 ("scalarrepl", "Scalar Replacement of Aggregates (DT)"),
294 ("scalarrepl-ssa", "Scalar Replacement of Aggregates (SSAUp)"),
295 ("sccp", "Sparse Conditional Constant Propagation"),
296 ("simplify-libcalls", "Simplify well-known library calls"),
297 ("simplifycfg", "Simplify the CFG"),
298 ("sink", "Code sinking"),
299 ("strip", "Strip all symbols from a module"),
300 ("strip-dead-debug-info", "Strip debug info for unused symbols"),
301 ("strip-dead-prototypes", "Strip Unused Function Prototypes"),
302 ("strip-debug-declare", "Strip all llvm.dbg.declare intrinsics"),
303 ("strip-nondebug", "Strip all symbols, except dbg symbols, from a module"),
304 ("sroa", "Scalar Replacement of Aggregates"),
305 ("tailcallelim", "Tail Call Elimination"),
308 /** Utility Passes */
309 static utility_passes : &'static [(&'static str, &'static str)] = &'static [
310 ("instnamer", "Assign names to anonymous instructions"),
311 ("verify", "Module Verifier"),
316 let mut failed = ~[];
317 unsafe { llvm::LLVMInitializePasses(); }
318 for &(name,_) in analysis_passes.iter() {
319 let pass = create_pass(name);
323 unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
326 for &(name,_) in transform_passes.iter() {
327 let pass = create_pass(name);
331 unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
334 for &(name,_) in utility_passes.iter() {
335 let pass = create_pass(name);
339 unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
343 if failed.len() > 0 {
344 io::println("Some passes don't exist:");
345 for &n in failed.iter() {