about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorBrandon Edens <brandonedens@gmail.com>2016-03-27 12:42:47 -0700
committerBrandon Edens <brandonedens@gmail.com>2016-04-28 23:08:30 -0700
commitb1337d309a67e34c1452b4a9a378a23dbd8b3573 (patch)
tree69983bbeb4cc6ccfcd65f19f010f06ad8b8ba40d /src
parent8da2bcac5db1e091b90cceb19d0496f0f7501c88 (diff)
downloadrust-b1337d309a67e34c1452b4a9a378a23dbd8b3573.tar.gz
rust-b1337d309a67e34c1452b4a9a378a23dbd8b3573.zip
Add opt-level options for optimizing for size and minimum size. This attempts
to mimic the behavior of clang's options Os and Oz.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/session/config.rs22
-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
4 files changed, 69 insertions, 19 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 9f29f9050e6..6ade74790a5 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,15 +1127,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             }
             OptLevel::Default
         } else {
-            match cg.opt_level {
+            match cg.opt_level.as_ref().map(String::as_ref) {
                 None => OptLevel::No,
-                Some(0) => OptLevel::No,
-                Some(1) => OptLevel::Less,
-                Some(2) => OptLevel::Default,
-                Some(3) => OptLevel::Aggressive,
+                Some("0") => OptLevel::No,
+                Some("1") => OptLevel::Less,
+                Some("2") => OptLevel::Default,
+                Some("3") => OptLevel::Aggressive,
+                Some("s") => OptLevel::Size,
+                Some("z") => OptLevel::SizeMin,
                 Some(arg) => {
                     early_error(error_format, &format!("optimization level needs to be \
-                                                      between 0-3 (instead was `{}`)",
+                                                      between 0-3, s, or z (instead was `{}`)",
                                                      arg));
                 }
             }
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
 }