]> git.lizzy.rs Git - rust.git/blob - src/librustc/back/passes.rs
Change 'print(fmt!(...))' to printf!/printfln! in src/lib*
[rust.git] / src / librustc / back / passes.rs
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.
4 //
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.
10
11 use std::str;
12 use std::io;
13
14 use driver::session::{OptLevel, No, Less, Aggressive};
15 use driver::session::{Session};
16 use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
17 use lib::llvm::llvm;
18 use lib;
19
20 pub struct PassManager {
21     priv llpm: PassManagerRef
22 }
23
24 impl Drop for PassManager {
25     fn drop(&self) {
26         unsafe {
27             llvm::LLVMDisposePassManager(self.llpm);
28         }
29     }
30 }
31
32 impl PassManager {
33     pub fn new(td: TargetDataRef) -> PassManager {
34         unsafe {
35             let pm = PassManager {
36                 llpm: llvm::LLVMCreatePassManager()
37             };
38             llvm::LLVMAddTargetData(td, pm.llpm);
39
40             return pm;
41         }
42     }
43
44     pub fn add_pass(&mut self, pass:PassRef) {
45         unsafe {
46             llvm::LLVMAddPass(self.llpm, pass);
47         }
48     }
49
50     pub fn add_pass_from_name(&mut self, name:&str) {
51         let pass = create_pass(name).unwrap();
52         self.add_pass(pass);
53     }
54
55     pub fn run(&self, md:ModuleRef) -> bool {
56         unsafe {
57             llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
58         }
59     }
60 }
61
62 pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
63     let mut passes = ~[];
64
65     // mostly identical to clang 3.3, all differences are documented with comments
66
67     if level != No {
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");
77     }
78
79     passes.push(~"basiccg");
80
81     if level != No {
82         passes.push(~"prune-eh");
83     }
84
85     passes.push(~"inline-cost");
86
87     if level == No || level == Less {
88         passes.push(~"always-inline");
89     } else {
90         passes.push(~"inline");
91     }
92
93     if level != No {
94         passes.push(~"functionattrs");
95         if level == Aggressive {
96             passes.push(~"argpromotion");
97         }
98         passes.push(~"sroa");
99         passes.push(~"domtree");
100         passes.push(~"early-cse");
101         passes.push(~"simplify-libcalls");
102         passes.push(~"lazy-value-info");
103         passes.push(~"jump-threading");
104         passes.push(~"correlated-propagation");
105         passes.push(~"simplifycfg");
106         passes.push(~"instcombine");
107         passes.push(~"tailcallelim");
108         passes.push(~"simplifycfg");
109         passes.push(~"reassociate");
110         passes.push(~"domtree");
111         passes.push(~"loops");
112         passes.push(~"loop-simplify");
113         passes.push(~"lcssa");
114         passes.push(~"loop-rotate");
115         passes.push(~"licm");
116         passes.push(~"lcssa");
117         passes.push(~"loop-unswitch");
118         passes.push(~"instcombine");
119         passes.push(~"scalar-evolution");
120         passes.push(~"loop-simplify");
121         passes.push(~"lcssa");
122         passes.push(~"indvars");
123         passes.push(~"loop-idiom");
124         passes.push(~"loop-deletion");
125         if level == Aggressive {
126             passes.push(~"loop-simplify");
127             passes.push(~"lcssa");
128             passes.push(~"loop-vectorize");
129             passes.push(~"loop-simplify");
130             passes.push(~"lcssa");
131             passes.push(~"scalar-evolution");
132             passes.push(~"loop-simplify");
133             passes.push(~"lcssa");
134         }
135         if level != Less {
136             passes.push(~"loop-unroll");
137             passes.push(~"memdep");
138             passes.push(~"gvn");
139         }
140         passes.push(~"memdep");
141         passes.push(~"memcpyopt");
142         passes.push(~"sccp");
143         passes.push(~"instcombine");
144         passes.push(~"lazy-value-info");
145         passes.push(~"jump-threading");
146         passes.push(~"correlated-propagation");
147         passes.push(~"domtree");
148         passes.push(~"memdep");
149         passes.push(~"dse");
150         passes.push(~"adce");
151         passes.push(~"simplifycfg");
152         passes.push(~"instcombine");
153         // clang does `strip-dead-prototypes` here, since it does not emit them
154     }
155
156     // rustc emits dead prototypes, so always ask LLVM to strip them
157     passes.push(~"strip-dead-prototypes");
158
159     if level != Less {
160         passes.push(~"globaldce");
161         passes.push(~"constmerge");
162     }
163
164     passes
165 }
166
167 pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
168     for pass_list.iter().advance |nm| {
169         match create_pass(*nm) {
170             Some(p) => pm.add_pass(p),
171             None    => sess.warn(fmt!("Unknown pass %s", *nm))
172         }
173     }
174 }
175
176 pub fn create_pass(name:&str) -> Option<PassRef> {
177     do str::as_c_str(name) |s| {
178         unsafe {
179             let p = llvm::LLVMCreatePass(s);
180             if p.is_null() {
181                 None
182             } else {
183                 Some(p)
184             }
185         }
186     }
187 }
188
189 pub fn list_passes() {
190     io::println("\nAvailable Passes:");
191
192     io::println("\nAnalysis Passes:");
193     for analysis_passes.iter().advance |&(name, desc)| {
194         printfln!("    %-30s -- %s", name, desc);
195     }
196     io::println("\nTransformation Passes:");
197     for transform_passes.iter().advance |&(name, desc)| {
198         printfln!("    %-30s -- %s", name, desc);
199     }
200     io::println("\nUtility Passes:");
201     for utility_passes.iter().advance |&(name, desc)| {
202         printfln!("    %-30s -- %s", name, desc);
203     }
204 }
205
206 /** Analysis Passes */
207 pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
208     ("aa-eval",                         "Exhausive Alias Analysis Precision Evaluator"),
209     ("asan",                            "AddressSanitizer"),
210     ("basicaa",                         "Basic Alias Analysis"),
211     ("basiccg",                         "Basic CallGraph Construction"),
212     ("block-freq",                      "Block Frequency Analysis"),
213     ("cost-model",                      "Cost Model Analysis"),
214     ("count-aa",                        "Count Alias Analysis Query Responses"),
215     ("da",                              "Dependence Analysis"),
216     ("debug-aa",                        "AA Use Debugger"),
217     ("domfrontier",                     "Dominance Frontier Construction"),
218     ("domtree",                         "Dominator Tree Construction"),
219     ("globalsmodref-aa",                "Simple mod/ref analysis for globals"),
220     ("instcount",                       "Count the various types of Instructions"),
221     ("intervals",                       "Interval Partition Construction"),
222     ("iv-users",                        "Induction Variable Users"),
223     ("lazy-value-info",                 "Lazy Value Information Analysis"),
224     ("libcall-aa",                      "LibCall Alias Analysis"),
225     ("lint",                            "Statically lint-check LLVM IR"),
226     ("loops",                           "Natural Loop Information"),
227     ("memdep",                          "Memory Dependence Analysis"),
228     ("module-debuginfo",                "Decodes module-level debug info"),
229     ("profile-estimator",               "Estimate profiling information"),
230     ("profile-loader",                  "Load profile information from llvmprof.out"),
231     ("profile-verifier",                "Verify profiling information"),
232     ("regions",                         "Detect single entry single exit regions"),
233     ("scalar-evolution",                "Scalar Evolution Analysis"),
234     ("scev-aa",                         "Scalar Evolution-based Alias Analysis"),
235     ("tbaa",                            "Type-Based Alias Analysis"),
236     ("tsan",                            "ThreadSanitizer"),
237 ];
238
239 /** Transformation Passes */
240 pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
241     ("adce",                            "Aggressive Dead Code Elimination"),
242     ("always-inline",                   "Inliner for #[inline] functions"),
243     ("argpromotion",                    "Promote 'by reference' arguments to scalars"),
244     ("bb-vectorize",                    "Basic-Block Vectorization"),
245     ("block-placement",                 "Profile Guided Basic Block Placement"),
246     ("bounds-checking",                 "Run-time bounds checking"),
247     ("break-crit-edges",                "Break critical edges in CFG"),
248     ("codegenprepare",                  "Optimize for code generation"),
249     ("constmerge",                      "Merge Duplicate Global Constants"),
250     ("constprop",                       "Simple constant propagation"),
251     ("correlated-propagation",          "Value Propagation"),
252     ("da",                              "Data Layout"),
253     ("dce",                             "Dead Code Elimination"),
254     ("deadargelim",                     "Dead Argument Elimination"),
255     ("die",                             "Dead Instruction Elimination"),
256     ("dse",                             "Dead Store Elimination"),
257     ("early-cse",                       "Early CSE"),
258     ("functionattrs",                   "Deduce function attributes"),
259     ("globaldce",                       "Dead Global Elimination"),
260     ("globalopt",                       "Global Variable Optimizer"),
261     ("gvn",                             "Global Value Numbering"),
262     ("indvars",                         "Canonicalize Induction Variables"),
263     ("inline",                          "Function Integration/Inlining"),
264     ("insert-edge-profiling",           "Insert instrumentation for edge profiling"),
265     ("insert-gcov-profiling",           "Insert instrumentation for GCOV profiling"),
266     ("insert-optimal-edge-profiling",   "Insert optimal instrumentation for edge profiling"),
267     ("instcombine",                     "Combine redundant instructions"),
268     ("instsimplify",                    "Remove redundant instructions"),
269     ("ipconstprop",                     "Interprocedural constant propagation"),
270     ("ipsccp",                          "Interprocedural Sparse Conditional Constant Propagation"),
271     ("jump-threading",                  "Jump Threading"),
272     ("lcssa",                           "Loop-Closed SSA Form Pass"),
273     ("licm",                            "Loop Invariant Code Motion"),
274     ("loop-deletion",                   "Delete dead loops"),
275     ("loop-extract",                    "Extract loops into new functions"),
276     ("loop-extract-single",             "Extract at most one loop into a new function"),
277     ("loop-idiom",                      "Recognise loop idioms"),
278     ("loop-instsimplify",               "Simplify instructions in loops"),
279     ("loop-reduce",                     "Loop Strength Reduction"),
280     ("loop-rotate",                     "Rotate Loops"),
281     ("loop-simplify",                   "Canonicalize natural loops"),
282     ("loop-unroll",                     "Unroll loops"),
283     ("loop-unswitch",                   "Unswitch loops"),
284     ("loop-vectorize",                  "Loop Vectorization"),
285     ("lower-expect",                    "Lower 'expect' Intrinsics"),
286     ("mem2reg",                         "Promote Memory to Register"),
287     ("memcpyopt",                       "MemCpy Optimization"),
288     ("mergefunc",                       "Merge Functions"),
289     ("mergereturn",                     "Unify function exit nodes"),
290     ("partial-inliner",                 "Partial Inliner"),
291     ("prune-eh",                        "Remove unused exception handling info"),
292     ("reassociate",                     "Reassociate expressions"),
293     ("reg2mem",                         "Demote all values to stack slots"),
294     ("scalarrepl",                      "Scalar Replacement of Aggregates (DT)"),
295     ("scalarrepl-ssa",                  "Scalar Replacement of Aggregates (SSAUp)"),
296     ("sccp",                            "Sparse Conditional Constant Propagation"),
297     ("simplify-libcalls",               "Simplify well-known library calls"),
298     ("simplifycfg",                     "Simplify the CFG"),
299     ("sink",                            "Code sinking"),
300     ("strip",                           "Strip all symbols from a module"),
301     ("strip-dead-debug-info",           "Strip debug info for unused symbols"),
302     ("strip-dead-prototypes",           "Strip Unused Function Prototypes"),
303     ("strip-debug-declare",             "Strip all llvm.dbg.declare intrinsics"),
304     ("strip-nondebug",                  "Strip all symbols, except dbg symbols, from a module"),
305     ("sroa",                            "Scalar Replacement of Aggregates"),
306     ("tailcallelim",                    "Tail Call Elimination"),
307 ];
308
309 /** Utility Passes */
310 static utility_passes : &'static [(&'static str, &'static str)] = &'static [
311     ("instnamer",                       "Assign names to anonymous instructions"),
312     ("verify",                          "Module Verifier"),
313 ];
314
315 #[test]
316 fn passes_exist() {
317     let mut failed = ~[];
318     unsafe { llvm::LLVMInitializePasses(); }
319     for analysis_passes.iter().advance |&(name,_)| {
320         let pass = create_pass(name);
321         if !pass.is_some() {
322             failed.push(name);
323         } else {
324             unsafe { llvm::LLVMDestroyPass(pass.get()) }
325         }
326     }
327     for transform_passes.iter().advance |&(name,_)| {
328         let pass = create_pass(name);
329         if !pass.is_some() {
330             failed.push(name);
331         } else {
332             unsafe { llvm::LLVMDestroyPass(pass.get()) }
333         }
334     }
335     for utility_passes.iter().advance |&(name,_)| {
336         let pass = create_pass(name);
337         if !pass.is_some() {
338             failed.push(name);
339         } else {
340             unsafe { llvm::LLVMDestroyPass(pass.get()) }
341         }
342     }
343
344     if failed.len() > 0 {
345         io::println("Some passes don't exist:");
346         for failed.iter().advance |&n| {
347             printfln!("    %s", n);
348         }
349         fail!();
350     }
351 }