Skip to content

Commit 206ad61

Browse files
committed
auto merge of #8894 : alexcrichton/rust/faster, r=thestinger
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. I would consider this as closing #8890. I don't think that we should change the default inlining threshold because LLVM/clang will probably have chosen those numbers more carefully than we would. Regardless, here's the performance numbers from this commit: ``` $ ./x86_64-apple-darwin/stage0/bin/rustc ./gistfile1.rs --test --opt-level=3 -o before warning: no debug symbols in executable (-arch x86_64) $ ./before --bench running 1 test test bench::aes_bench_x8 ... bench: 1602 ns/iter (+/- 66) = 7990 MB/s test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured $ ./x86_64-apple-darwin/stage1/bin/rustc ./gistfile1.rs --test --opt-level=3 -o after warning: no debug symbols in executable (-arch x86_64) $ ./after --bench running 1 test test bench::aes_bench_x8 ... bench: 2103 ns/iter (+/- 175) = 6086 MB/s test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured $ ./x86_64-apple-darwin/stage1/bin/rustc ./gistfile1.rs --test --opt-level=3 -o after --llvm-args '-inline-threshold=225' warning: no debug symbols in executable (-arch x86_64) $ ./after --bench running 1 test test bench::aes_bench_x8 ... bench: 1600 ns/iter (+/- 71) = 8000 MB/s test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured ```
2 parents 29449e3 + 8d12673 commit 206ad61

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)