Skip to content

Commit e946b4f

Browse files
committed
auto merge of #6778 : Aatch/rust/pass-refactor, r=graydon
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.
2 parents e0d6486 + 4ad0b8a commit e946b4f

File tree

11 files changed

+719
-100
lines changed

11 files changed

+719
-100
lines changed

Makefile.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ DRIVER_CRATE := $(S)src/driver/driver.rs
275275

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

280280
define DEF_LLVM_VARS
281281
# The configure script defines these variables with the target triples

mk/rustllvm.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ LLVM_EXTRA_INCDIRS_$(1)= -iquote $(S)src/llvm/include \
2222
-iquote llvm/$(1)/include
2323
endif
2424

25-
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, RustWrapper.cpp)
25+
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, RustWrapper.cpp PassWrapper.cpp)
2626

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

src/librustc/back/link.rs

+18-52
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,11 @@ pub mod write {
180180
use driver::session::Session;
181181
use driver::session;
182182
use lib::llvm::llvm;
183-
use lib::llvm::{False, ModuleRef, mk_pass_manager, mk_target_data};
183+
use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
184184
use lib;
185185

186+
use back::passes;
187+
186188
use core::libc::{c_int, c_uint};
187189
use core::path::Path;
188190
use core::run;
@@ -202,16 +204,12 @@ pub mod write {
202204
unsafe {
203205
let opts = sess.opts;
204206
if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
205-
let mut pm = mk_pass_manager();
206207
let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
208+
let pm = mk_pass_manager();
207209
llvm::LLVMAddTargetData(td.lltd, pm.llpm);
208-
// FIXME (#2812): run the linter here also, once there are llvm-c
209-
// bindings for it.
210210

211211
// Generate a pre-optimization intermediate file if -save-temps
212212
// was specified.
213-
214-
215213
if opts.save_temps {
216214
match output_type {
217215
output_type_bitcode => {
@@ -230,50 +228,22 @@ pub mod write {
230228
}
231229
}
232230
}
233-
if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
234-
// FIXME (#2396): This is mostly a copy of the bits of opt's -O2
235-
// that are available in the C api.
236-
// Also: We might want to add optimization levels like -O1, -O2,
237-
// -Os, etc
238-
// Also: Should we expose and use the pass lists used by the opt
239-
// tool?
240-
241-
if opts.optimize != session::No {
242-
let fpm = mk_pass_manager();
243-
llvm::LLVMAddTargetData(td.lltd, fpm.llpm);
244-
245-
let FPMB = llvm::LLVMPassManagerBuilderCreate();
246-
llvm::LLVMPassManagerBuilderSetOptLevel(FPMB, 2u as c_uint);
247-
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(
248-
FPMB, fpm.llpm);
249-
llvm::LLVMPassManagerBuilderDispose(FPMB);
250-
251-
llvm::LLVMRunPassManager(fpm.llpm, llmod);
252-
let mut threshold = 225;
253-
if opts.optimize == session::Aggressive { threshold = 275; }
254-
255-
let MPMB = llvm::LLVMPassManagerBuilderCreate();
256-
llvm::LLVMPassManagerBuilderSetOptLevel(MPMB,
257-
opts.optimize as
258-
c_uint);
259-
llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, False);
260-
llvm::LLVMPassManagerBuilderSetDisableUnitAtATime(MPMB,
261-
False);
262-
llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(MPMB,
263-
False);
264-
llvm::LLVMPassManagerBuilderSetDisableSimplifyLibCalls(MPMB,
265-
False);
266-
267-
if threshold != 0u {
268-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold
269-
(MPMB, threshold as c_uint);
270-
}
271-
llvm::LLVMPassManagerBuilderPopulateModulePassManager(
272-
MPMB, pm.llpm);
273231

274-
llvm::LLVMPassManagerBuilderDispose(MPMB);
232+
let mut mpm = passes::PassManager::new(td.lltd);
233+
234+
if !sess.no_verify() {
235+
mpm.addPass(llvm::LLVMCreateVerifierPass());
275236
}
276-
if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
237+
238+
if sess.lint_llvm() {
239+
mpm.addPass(llvm::LLVMCreateLintPass());
240+
}
241+
242+
passes::populatePassManager(&mut mpm, opts.optimize);
243+
244+
debug!("Running Module Optimization Pass");
245+
mpm.run(llmod);
246+
277247
if is_object_or_assembly_or_exe(output_type) || opts.jit {
278248
let LLVMOptNone = 0 as c_int; // -O0
279249
let LLVMOptLess = 1 as c_int; // -O1
@@ -312,12 +282,9 @@ pub mod write {
312282
// Always output the bitcode file with --save-temps
313283

314284
let filename = output.with_filetype("opt.bc");
315-
llvm::LLVMRunPassManager(pm.llpm, llmod);
316285
str::as_c_str(filename.to_str(), |buf| {
317286
llvm::LLVMWriteBitcodeToFile(llmod, buf)
318287
});
319-
pm = mk_pass_manager();
320-
321288
// Save the assembly file if -S is used
322289
if output_type == output_type_assembly {
323290
WriteOutputFile(
@@ -377,7 +344,6 @@ pub mod write {
377344
} else {
378345
// If only a bitcode file is asked for by using the
379346
// '--emit-llvm' flag, then output it here
380-
llvm::LLVMRunPassManager(pm.llpm, llmod);
381347
str::as_c_str(output.to_str(),
382348
|buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) );
383349
}

src/librustc/back/passes.rs

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright 2012 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 core::prelude::*;
12+
13+
use driver::session;
14+
use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
15+
use lib::llvm::llvm;
16+
use lib;
17+
18+
pub struct PassManager {
19+
priv llpm: PassManagerRef
20+
}
21+
22+
impl Drop for PassManager {
23+
fn finalize(&self) {
24+
unsafe {
25+
llvm::LLVMDisposePassManager(self.llpm);
26+
}
27+
}
28+
}
29+
30+
impl PassManager {
31+
pub fn new(td: TargetDataRef) -> PassManager {
32+
unsafe {
33+
let pm = PassManager {
34+
llpm: llvm::LLVMCreatePassManager()
35+
};
36+
llvm::LLVMAddTargetData(td, pm.llpm);
37+
38+
return pm;
39+
}
40+
}
41+
42+
pub fn addPass(&mut self, pass:PassRef) {
43+
unsafe {
44+
llvm::LLVMAddPass(self.llpm, pass);
45+
}
46+
}
47+
48+
pub fn run(&self, md:ModuleRef) -> bool {
49+
unsafe {
50+
llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
51+
}
52+
}
53+
}
54+
55+
56+
pub fn populatePassManager(pm: &mut PassManager, level:session::OptLevel) {
57+
unsafe {
58+
// We add a lot of normally-unused prototypes, so always strip them
59+
// straight away, later passes will get rid of any that are optimized
60+
// away
61+
pm.addPass(llvm::LLVMCreateStripDeadPrototypesPass());
62+
if level == session::No {
63+
pm.addPass(llvm::LLVMCreateAlwaysInlinerPass());
64+
65+
return;
66+
}
67+
68+
//NOTE: Add library info
69+
70+
pm.addPass(llvm::LLVMCreateTypeBasedAliasAnalysisPass());
71+
pm.addPass(llvm::LLVMCreateBasicAliasAnalysisPass());
72+
73+
pm.addPass(llvm::LLVMCreateSROAPass());
74+
pm.addPass(llvm::LLVMCreateEarlyCSEPass());
75+
pm.addPass(llvm::LLVMCreateLowerExpectIntrinsicPass());
76+
77+
pm.addPass(llvm::LLVMCreateGlobalOptimizerPass());
78+
pm.addPass(llvm::LLVMCreateIPSCCPPass());
79+
pm.addPass(llvm::LLVMCreateDeadArgEliminationPass());
80+
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
81+
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());
82+
83+
pm.addPass(llvm::LLVMCreatePruneEHPass());
84+
85+
if level == session::Aggressive {
86+
// Do this before inlining, since inlining might
87+
// make minor changes to functions that mean they
88+
// can't be merged, despite being almost identical
89+
pm.addPass(llvm::LLVMCreateMergeFunctionsPass());
90+
}
91+
92+
match level {
93+
session::Less => pm.addPass(llvm::LLVMCreateFunctionInliningPass(200)),
94+
session::Default => pm.addPass(llvm::LLVMCreateFunctionInliningPass(225)),
95+
session::Aggressive => pm.addPass(llvm::LLVMCreateFunctionInliningPass(275)),
96+
session::No => ()
97+
}
98+
99+
pm.addPass(llvm::LLVMCreateFunctionAttrsPass());
100+
101+
if level == session::Aggressive {
102+
pm.addPass(llvm::LLVMCreateArgumentPromotionPass());
103+
}
104+
105+
pm.addPass(llvm::LLVMCreateEarlyCSEPass());
106+
pm.addPass(llvm::LLVMCreateSimplifyLibCallsPass());
107+
pm.addPass(llvm::LLVMCreateJumpThreadingPass());
108+
pm.addPass(llvm::LLVMCreateCorrelatedValuePropagationPass());
109+
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());
110+
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
111+
112+
pm.addPass(llvm::LLVMCreateTailCallEliminationPass());
113+
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());
114+
pm.addPass(llvm::LLVMCreateReassociatePass());
115+
pm.addPass(llvm::LLVMCreateLoopRotatePass());
116+
pm.addPass(llvm::LLVMCreateLICMPass());
117+
118+
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
119+
pm.addPass(llvm::LLVMCreateIndVarSimplifyPass());
120+
pm.addPass(llvm::LLVMCreateLoopIdiomPass());
121+
pm.addPass(llvm::LLVMCreateLoopDeletionPass());
122+
123+
if level == session::Aggressive {
124+
pm.addPass(llvm::LLVMCreateLoopVectorizePass());
125+
}
126+
pm.addPass(llvm::LLVMCreateLoopUnrollPass());
127+
128+
if level != session::Less {
129+
pm.addPass(llvm::LLVMCreateGVNPass());
130+
}
131+
pm.addPass(llvm::LLVMCreateMemCpyOptPass());
132+
pm.addPass(llvm::LLVMCreateSCCPPass());
133+
134+
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
135+
pm.addPass(llvm::LLVMCreateJumpThreadingPass());
136+
pm.addPass(llvm::LLVMCreateCorrelatedValuePropagationPass());
137+
pm.addPass(llvm::LLVMCreateDeadStoreEliminationPass());
138+
139+
pm.addPass(llvm::LLVMCreateBBVectorizePass());
140+
pm.addPass(llvm::LLVMCreateInstructionCombiningPass());
141+
pm.addPass(llvm::LLVMCreateEarlyCSEPass());
142+
143+
pm.addPass(llvm::LLVMCreateLoopUnrollPass());
144+
145+
pm.addPass(llvm::LLVMCreateAggressiveDCEPass());
146+
pm.addPass(llvm::LLVMCreateCFGSimplificationPass());
147+
pm.addPass(llvm::LLVMCreateInstructionSimplifierPass());
148+
149+
if level != session::Less {
150+
pm.addPass(llvm::LLVMCreateGlobalDCEPass());
151+
pm.addPass(llvm::LLVMCreateConstantMergePass());
152+
}
153+
}
154+
}

src/librustc/driver/session.rs

+5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub static extra_debug_info: uint = 1 << 21;
6969
pub static statik: uint = 1 << 22;
7070
pub static print_link_args: uint = 1 << 23;
7171
pub static no_debug_borrows: uint = 1 << 24;
72+
pub static lint_llvm : uint = 1 << 25;
7273

7374
pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
7475
~[(~"verbose", ~"in general, enable more debug printouts", verbose),
@@ -107,6 +108,9 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
107108
(~"no-debug-borrows",
108109
~"do not show where borrow checks fail",
109110
no_debug_borrows),
111+
(~"lint-llvm",
112+
~"Run the LLVM lint pass on the pre-optimization IR",
113+
lint_llvm),
110114
]
111115
}
112116

@@ -265,6 +269,7 @@ pub impl Session_ {
265269
fn meta_stats(@self) -> bool { self.debugging_opt(meta_stats) }
266270
fn asm_comments(@self) -> bool { self.debugging_opt(asm_comments) }
267271
fn no_verify(@self) -> bool { self.debugging_opt(no_verify) }
272+
fn lint_llvm(@self) -> bool { self.debugging_opt(lint_llvm) }
268273
fn trace(@self) -> bool { self.debugging_opt(trace) }
269274
fn coherence(@self) -> bool { self.debugging_opt(coherence) }
270275
fn borrowck_stats(@self) -> bool { self.debugging_opt(borrowck_stats) }

0 commit comments

Comments
 (0)