about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/session/config.rs31
-rw-r--r--src/librustc_llvm/lib.rs9
-rw-r--r--src/librustc_trans/back/write.rs46
-rw-r--r--src/librustc_trans/declare.rs11
-rw-r--r--src/test/run-make/debug-assertions/Makefile4
-rw-r--r--src/test/run-make/emit/Makefile6
6 files changed, 86 insertions, 21 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 9f29f9050e6..b8dd750d3f1 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -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)]
@@ -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,
@@ -1125,13 +1127,20 @@ 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,
+                (Some("s"), false) | (Some("z"), false) => {
+                    early_error(error_format, &format!("the optimizations s or z are only \
+                                                        accepted on the nightly compiler"));
+                },
+                (Some(arg), _) => {
                     early_error(error_format, &format!("optimization level needs to be \
                                                       between 0-3 (instead was `{}`)",
                                                      arg));
@@ -1304,7 +1313,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,
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 526b6bf68be..ea0d8eae75d 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -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::*;
@@ -377,6 +378,14 @@ pub enum CodeGenOptLevel {
 
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
+pub enum CodeGenOptSize {
+    CodeGenOptSizeNone = 0,
+    CodeGenOptSizeDefault = 1,
+    CodeGenOptSizeAggressive = 2,
+}
+
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
 pub enum RelocMode {
     RelocDefault = 0,
     RelocStatic = 1,
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 8a915f04405..777245c4e0c 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -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,
     }
 }
 
@@ -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,
@@ -268,6 +280,7 @@ impl ModuleConfig {
             tm: tm,
             passes: passes,
             opt_level: None,
+            opt_size: None,
 
             emit_no_opt_bc: false,
             emit_bc: false,
@@ -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 {
@@ -991,13 +1005,19 @@ 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);
 
@@ -1005,22 +1025,28 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
     // 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);
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index eb520fe744a..9a4d20ca301 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -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
 }
 
diff --git a/src/test/run-make/debug-assertions/Makefile b/src/test/run-make/debug-assertions/Makefile
index 71297562768..76ada90f1e2 100644
--- a/src/test/run-make/debug-assertions/Makefile
+++ b/src/test/run-make/debug-assertions/Makefile
@@ -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
diff --git a/src/test/run-make/emit/Makefile b/src/test/run-make/emit/Makefile
index be34028fe1d..e0b57107e5b 100644
--- a/src/test/run-make/emit/Makefile
+++ b/src/test/run-make/emit/Makefile
@@ -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
@@ -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