Skip to content

Commit 8d12673

Browse files
committed
Tweak pass management and add some more options
The only changes to the default passes is that O1 now doesn't run the inline pass, just always-inline with lifetime intrinsics. O2 also now has a threshold of 225 instead of 275. Otherwise the default passes being run is the same. I've also added a few more options for configuring the pass pipeline. Namely you can now specify arguments to LLVM directly via the `--llvm-args` command line option which operates similarly to `--passes`. I also added the ability to turn off pre-population of the pass manager in case you want to run *only* your own passes.
1 parent 974f854 commit 8d12673

File tree

5 files changed

+100
-68
lines changed

5 files changed

+100
-68
lines changed

src/librustc/back/link.rs

Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ pub mod write {
216216
use lib;
217217

218218
use std::c_str::ToCStr;
219-
use std::libc::c_uint;
219+
use std::libc::{c_uint, c_int};
220220
use std::path::Path;
221221
use std::run;
222222
use std::str;
@@ -257,17 +257,7 @@ pub mod write {
257257
}
258258
}
259259

260-
// Copy what clan does by turning on loop vectorization at O2 and
261-
// slp vectorization at O3
262-
let vectorize_loop = !sess.no_vectorize_loops() &&
263-
(sess.opts.optimize == session::Default ||
264-
sess.opts.optimize == session::Aggressive);
265-
let vectorize_slp = !sess.no_vectorize_slp() &&
266-
sess.opts.optimize == session::Aggressive;
267-
llvm::LLVMRustSetLLVMOptions(sess.print_llvm_passes(),
268-
vectorize_loop,
269-
vectorize_slp,
270-
sess.time_llvm_passes());
260+
configure_llvm(sess);
271261

272262
let OptLevel = match sess.opts.optimize {
273263
session::No => lib::llvm::CodeGenLevelNone,
@@ -293,12 +283,9 @@ pub mod write {
293283
// Create the two optimizing pass managers. These mirror what clang
294284
// does, and are by populated by LLVM's default PassManagerBuilder.
295285
// Each manager has a different set of passes, but they also share
296-
// some common passes. Each one is initialized with the analyis
297-
// passes the target requires, and then further passes are added.
286+
// some common passes.
298287
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
299288
let mpm = llvm::LLVMCreatePassManager();
300-
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
301-
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
302289

303290
// If we're verifying or linting, add them to the function pass
304291
// manager.
@@ -308,32 +295,11 @@ pub mod write {
308295
if !sess.no_verify() { assert!(addpass("verify")); }
309296
if sess.lint_llvm() { assert!(addpass("lint")); }
310297

311-
// Create the PassManagerBuilder for LLVM. We configure it with
312-
// reasonable defaults and prepare it to actually populate the pass
313-
// manager.
314-
let builder = llvm::LLVMPassManagerBuilderCreate();
315-
match sess.opts.optimize {
316-
session::No => {
317-
// Don't add lifetime intrinsics add O0
318-
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
319-
}
320-
// numeric values copied from clang
321-
session::Less => {
322-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
323-
225);
324-
}
325-
session::Default | session::Aggressive => {
326-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
327-
275);
328-
}
298+
if !sess.no_prepopulate_passes() {
299+
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
300+
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
301+
populate_llvm_passess(fpm, mpm, llmod, OptLevel);
329302
}
330-
llvm::LLVMPassManagerBuilderSetOptLevel(builder, OptLevel as c_uint);
331-
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
332-
333-
// Use the builder to populate the function/module pass managers.
334-
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
335-
llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
336-
llvm::LLVMPassManagerBuilderDispose(builder);
337303

338304
for pass in sess.opts.custom_passes.iter() {
339305
do pass.with_c_str |s| {
@@ -424,6 +390,74 @@ pub mod write {
424390
sess.abort_if_errors();
425391
}
426392
}
393+
394+
unsafe fn configure_llvm(sess: Session) {
395+
// Copy what clan does by turning on loop vectorization at O2 and
396+
// slp vectorization at O3
397+
let vectorize_loop = !sess.no_vectorize_loops() &&
398+
(sess.opts.optimize == session::Default ||
399+
sess.opts.optimize == session::Aggressive);
400+
let vectorize_slp = !sess.no_vectorize_slp() &&
401+
sess.opts.optimize == session::Aggressive;
402+
403+
let mut llvm_c_strs = ~[];
404+
let mut llvm_args = ~[];
405+
let add = |arg: &str| {
406+
let s = arg.to_c_str();
407+
llvm_args.push(s.with_ref(|p| p));
408+
llvm_c_strs.push(s);
409+
};
410+
add("rustc"); // fake program name
411+
add("-arm-enable-ehabi");
412+
add("-arm-enable-ehabi-descriptors");
413+
if vectorize_loop { add("-vectorize-loops"); }
414+
if vectorize_slp { add("-vectorize-slp"); }
415+
if sess.time_llvm_passes() { add("-time-passes"); }
416+
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
417+
418+
for arg in sess.opts.llvm_args.iter() {
419+
add(*arg);
420+
}
421+
422+
do llvm_args.as_imm_buf |p, len| {
423+
llvm::LLVMRustSetLLVMOptions(len as c_int, p);
424+
}
425+
}
426+
427+
unsafe fn populate_llvm_passess(fpm: lib::llvm::PassManagerRef,
428+
mpm: lib::llvm::PassManagerRef,
429+
llmod: ModuleRef,
430+
opt: lib::llvm::CodeGenOptLevel) {
431+
// Create the PassManagerBuilder for LLVM. We configure it with
432+
// reasonable defaults and prepare it to actually populate the pass
433+
// manager.
434+
let builder = llvm::LLVMPassManagerBuilderCreate();
435+
match opt {
436+
lib::llvm::CodeGenLevelNone => {
437+
// Don't add lifetime intrinsics add O0
438+
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
439+
}
440+
lib::llvm::CodeGenLevelLess => {
441+
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
442+
}
443+
// numeric values copied from clang
444+
lib::llvm::CodeGenLevelDefault => {
445+
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
446+
225);
447+
}
448+
lib::llvm::CodeGenLevelAggressive => {
449+
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
450+
275);
451+
}
452+
}
453+
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
454+
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
455+
456+
// Use the builder to populate the function/module pass managers.
457+
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
458+
llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
459+
llvm::LLVMPassManagerBuilderDispose(builder);
460+
}
427461
}
428462

429463

src/librustc/driver/driver.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,13 +737,22 @@ pub fn build_session_options(binary: @str,
737737
}).collect()
738738
}
739739
};
740+
let llvm_args = match getopts::opt_maybe_str(matches, "llvm-args") {
741+
None => ~[],
742+
Some(s) => {
743+
s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
744+
s.trim().to_owned()
745+
}).collect()
746+
}
747+
};
740748

741749
let sopts = @session::options {
742750
crate_type: crate_type,
743751
is_static: statik,
744752
gc: gc,
745753
optimize: opt_level,
746754
custom_passes: custom_passes,
755+
llvm_args: llvm_args,
747756
debuginfo: debuginfo,
748757
extra_debuginfo: extra_debuginfo,
749758
lint_opts: lint_opts,
@@ -851,6 +860,8 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] {
851860
Appends to the default list of passes to run for the \
852861
specified current optimization level. A value of \
853862
\"list\" will list all of the available passes", "NAMES"),
863+
optopt("", "llvm-args", "A list of arguments to pass to llvm, comma \
864+
separated", "ARGS"),
854865
optopt( "", "out-dir",
855866
"Write output to compiler-chosen filename
856867
in <dir>", "DIR"),

src/librustc/driver/session.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ pub static once_fns: uint = 1 << 26;
7979
pub static print_llvm_passes: uint = 1 << 27;
8080
pub static no_vectorize_loops: uint = 1 << 28;
8181
pub static no_vectorize_slp: uint = 1 << 29;
82+
pub static no_prepopulate_passes: uint = 1 << 30;
8283

8384
pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
8485
~[(~"verbose", ~"in general, enable more debug printouts", verbose),
@@ -126,6 +127,10 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
126127
(~"print-llvm-passes",
127128
~"Prints the llvm optimization passes being run",
128129
print_llvm_passes),
130+
(~"no-prepopulate-passes",
131+
~"Don't pre-populate the pass managers with a list of passes, only use \
132+
the passes from --passes",
133+
no_prepopulate_passes),
129134
(~"no-vectorize-loops",
130135
~"Don't run the loop vectorization optimization passes",
131136
no_vectorize_loops),
@@ -152,6 +157,7 @@ pub struct options {
152157
gc: bool,
153158
optimize: OptLevel,
154159
custom_passes: ~[~str],
160+
llvm_args: ~[~str],
155161
debuginfo: bool,
156162
extra_debuginfo: bool,
157163
lint_opts: ~[(lint::lint, lint::level)],
@@ -320,6 +326,9 @@ impl Session_ {
320326
pub fn print_llvm_passes(@self) -> bool {
321327
self.debugging_opt(print_llvm_passes)
322328
}
329+
pub fn no_prepopulate_passes(@self) -> bool {
330+
self.debugging_opt(no_prepopulate_passes)
331+
}
323332
pub fn no_vectorize_loops(@self) -> bool {
324333
self.debugging_opt(no_vectorize_loops)
325334
}
@@ -351,6 +360,7 @@ pub fn basic_options() -> @options {
351360
gc: false,
352361
optimize: No,
353362
custom_passes: ~[],
363+
llvm_args: ~[],
354364
debuginfo: false,
355365
extra_debuginfo: false,
356366
lint_opts: ~[],

src/librustc/lib/llvm.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ pub enum AsmDialect {
191191
AD_Intel = 1
192192
}
193193

194+
#[deriving(Eq)]
194195
pub enum CodeGenOptLevel {
195196
CodeGenLevelNone = 0,
196197
CodeGenLevelLess = 1,
@@ -2123,10 +2124,7 @@ pub mod llvm {
21232124
pub fn LLVMRustPrintModule(PM: PassManagerRef,
21242125
M: ModuleRef,
21252126
Output: *c_char);
2126-
pub fn LLVMRustSetLLVMOptions(PrintPasses: bool,
2127-
VectorizeLoops: bool,
2128-
VectorizeSLP: bool,
2129-
TimePasses: bool);
2127+
pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: **c_char);
21302128
pub fn LLVMRustPrintPasses();
21312129
pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *c_char);
21322130
pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef,

src/rustllvm/PassWrapper.cpp

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -143,36 +143,15 @@ LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) {
143143
}
144144

145145
extern "C" void
146-
LLVMRustSetLLVMOptions(bool PrintPasses,
147-
bool VectorizeLoops,
148-
bool VectorizeSLP,
149-
bool TimePasses) {
146+
LLVMRustSetLLVMOptions(int Argc, char **Argv) {
150147
// Initializing the command-line options more than once is not allowed. So,
151148
// check if they've already been initialized. (This could happen if we're
152149
// being called from rustpkg, for example). If the arguments change, then
153150
// that's just kinda unfortunate.
154151
static bool initialized = false;
155152
if (initialized) return;
156-
157-
int argc = 3;
158-
const char *argv[20] = {"rustc",
159-
"-arm-enable-ehabi",
160-
"-arm-enable-ehabi-descriptors"};
161-
if (PrintPasses) {
162-
argv[argc++] = "-debug-pass";
163-
argv[argc++] = "Structure";
164-
}
165-
if (VectorizeLoops) {
166-
argv[argc++] = "-vectorize-loops";
167-
}
168-
if (VectorizeSLP) {
169-
argv[argc++] = "-vectorize-slp";
170-
}
171-
if (TimePasses) {
172-
argv[argc++] = "-time-passes";
173-
}
174-
cl::ParseCommandLineOptions(argc, argv);
175153
initialized = true;
154+
cl::ParseCommandLineOptions(Argc, Argv);
176155
}
177156

178157
extern "C" bool

0 commit comments

Comments
 (0)