Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CodeGen options to optimize for size. #32386

Merged
merged 4 commits into from
May 3, 2016
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ pub enum OptLevel {
No, // -O0
Less, // -O1
Default, // -O2
Aggressive // -O3
Aggressive, // -O3
Size, // -Os
SizeMin, // -Oz
}

#[derive(Clone, Copy, PartialEq)]
Expand Down Expand Up @@ -567,8 +569,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
debuginfo: Option<usize> = (None, parse_opt_uint,
"debug info emission level, 0 = no debug info, 1 = line tables only, \
2 = full debug info with variable and type information"),
opt_level: Option<usize> = (None, parse_opt_uint,
"optimize with possible levels 0-3"),
opt_level: Option<String> = (None, parse_opt_string,
"optimize with possible levels 0-3, s, or z"),
debug_assertions: Option<bool> = (None, parse_opt_bool,
"explicitly enable the cfg(debug_assertions) directive"),
inline_threshold: Option<usize> = (None, parse_opt_uint,
Expand Down Expand Up @@ -1125,13 +1127,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
}
OptLevel::Default
} else {
match cg.opt_level {
None => OptLevel::No,
Some(0) => OptLevel::No,
Some(1) => OptLevel::Less,
Some(2) => OptLevel::Default,
Some(3) => OptLevel::Aggressive,
Some(arg) => {
match (cg.opt_level.as_ref().map(String::as_ref),
nightly_options::is_nightly_build()) {
(None, _) => OptLevel::No,
(Some("0"), _) => OptLevel::No,
(Some("1"), _) => OptLevel::Less,
(Some("2"), _) => OptLevel::Default,
(Some("3"), _) => OptLevel::Aggressive,
(Some("s"), true) => OptLevel::Size,
(Some("z"), true) => OptLevel::SizeMin,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you tweak the error message here to indicate that nightly is required if s or z is passed on the stable/beta builds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added below and tested locally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I added a early exit for attempts to optimize for size on non-nightly.

(Some(arg), _) => {
early_error(error_format, &format!("optimization level needs to be \
between 0-3 (instead was `{}`)",
arg));
Expand Down Expand Up @@ -1304,7 +1309,7 @@ pub mod nightly_options {
is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
}

fn is_nightly_build() -> bool {
pub fn is_nightly_build() -> bool {
match get_unstable_features_setting() {
UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
_ => false,
Expand Down
9 changes: 9 additions & 0 deletions src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub use self::FileType::*;
pub use self::MetadataType::*;
pub use self::AsmDialect::*;
pub use self::CodeGenOptLevel::*;
pub use self::CodeGenOptSize::*;
pub use self::RelocMode::*;
pub use self::CodeGenModel::*;
pub use self::DiagnosticKind::*;
Expand Down Expand Up @@ -375,6 +376,14 @@ pub enum CodeGenOptLevel {
CodeGenLevelAggressive = 3,
}

#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum CodeGenOptSize {
CodeGenOptSizeNone = 0,
CodeGenOptSizeDefault = 1,
CodeGenOptSizeAggressive = 2,
}

#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum RelocMode {
Expand Down
46 changes: 36 additions & 10 deletions src/librustc_trans/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,15 @@ fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
config::OptLevel::Less => llvm::CodeGenLevelLess,
config::OptLevel::Default => llvm::CodeGenLevelDefault,
config::OptLevel::Aggressive => llvm::CodeGenLevelAggressive,
_ => llvm::CodeGenLevelDefault,
}
}

fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize {
match optimize {
config::OptLevel::Size => llvm::CodeGenOptSizeDefault,
config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive,
_ => llvm::CodeGenOptSizeNone,
}
}

Expand Down Expand Up @@ -237,6 +246,9 @@ pub struct ModuleConfig {
/// absolutely no optimizations (used for the metadata module).
opt_level: Option<llvm::CodeGenOptLevel>,

/// Some(level) to optimize binary size, or None to not affect program size.
opt_size: Option<llvm::CodeGenOptSize>,

// Flags indicating which outputs to produce.
emit_no_opt_bc: bool,
emit_bc: bool,
Expand Down Expand Up @@ -268,6 +280,7 @@ impl ModuleConfig {
tm: tm,
passes: passes,
opt_level: None,
opt_size: None,

emit_no_opt_bc: false,
emit_bc: false,
Expand Down Expand Up @@ -637,6 +650,7 @@ pub fn run_passes(sess: &Session,
let mut metadata_config = ModuleConfig::new(tm, vec!());

modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize));
modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize));

// Save all versions of the bytecode if we're saving our temporaries.
if sess.opts.cg.save_temps {
Expand Down Expand Up @@ -991,36 +1005,48 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
// reasonable defaults and prepare it to actually populate the pass
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
let opt = config.opt_level.unwrap_or(llvm::CodeGenLevelNone);
let opt_level = config.opt_level.unwrap_or(llvm::CodeGenLevelNone);
let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
let inline_threshold = config.inline_threshold;

llvm::LLVMRustConfigurePassManagerBuilder(builder, opt,
llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level,
config.merge_functions,
config.vectorize_slp,
config.vectorize_loop);
llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);

if opt_size != llvm::CodeGenOptSizeNone {
llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1);
}

llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);

// Here we match what clang does (kinda). For O0 we only inline
// always-inline functions (but don't add lifetime intrinsics), at O1 we
// inline with lifetime intrinsics, and O2+ we add an inliner with a
// thresholds copied from clang.
match (opt, inline_threshold) {
(_, Some(t)) => {
match (opt_level, opt_size, inline_threshold) {
(_, _, Some(t)) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
}
(llvm::CodeGenLevelNone, _) => {
(llvm::CodeGenLevelAggressive, _, _) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
}
(_, llvm::CodeGenOptSizeDefault, _) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75);
}
(_, llvm::CodeGenOptSizeAggressive, _) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
}
(llvm::CodeGenLevelNone, _, _) => {
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
}
(llvm::CodeGenLevelLess, _) => {
(llvm::CodeGenLevelLess, _, _) => {
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
}
(llvm::CodeGenLevelDefault, _) => {
(llvm::CodeGenLevelDefault, _, _) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
}
(llvm::CodeGenLevelAggressive, _) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
}
}

f(builder);
Expand Down
11 changes: 11 additions & 0 deletions src/librustc_trans/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty:
llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoRedZone)
}

match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) {
Some("s") => {
llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize);
},
Some("z") => {
llvm::SetFunctionAttribute(llfn, llvm::Attribute::MinSize);
llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize);
},
_ => {},
}

llfn
}

Expand Down
4 changes: 4 additions & 0 deletions src/test/run-make/debug-assertions/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ all:
$(call RUN,debug) good
$(RUSTC) debug.rs -C opt-level=3
$(call RUN,debug) good
$(RUSTC) debug.rs -C opt-level=s
$(call RUN,debug) good
$(RUSTC) debug.rs -C opt-level=z
$(call RUN,debug) good
$(RUSTC) debug.rs -O
$(call RUN,debug) good
$(RUSTC) debug.rs
Expand Down
6 changes: 6 additions & 0 deletions src/test/run-make/emit/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ all:
$(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs
$(RUSTC) -Copt-level=2 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs
$(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs
$(RUSTC) -Copt-level=s --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs
$(RUSTC) -Copt-level=z --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs
$(RUSTC) -Copt-level=0 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs
$(call RUN,test-26235) || exit 1
$(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs
Expand All @@ -13,3 +15,7 @@ all:
$(call RUN,test-26235) || exit 1
$(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs
$(call RUN,test-26235) || exit 1
$(RUSTC) -Copt-level=s --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs
$(call RUN,test-26235) || exit 1
$(RUSTC) -Copt-level=z --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs
$(call RUN,test-26235) || exit 1