about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
authorSimonas Kazlauskas <git@kazlauskas.me>2018-10-27 15:29:06 +0300
committerSimonas Kazlauskas <git@kazlauskas.me>2019-01-24 20:13:50 +0200
commitf38d0da89389c45067d37ba15e783c024088a09a (patch)
tree75260423c9caa95661d32a8bbdef5888f8591fa4 /src/librustc_codegen_llvm
parent095b44c83b540bb4dbf74be1cae604f4bae87989 (diff)
downloadrust-f38d0da89389c45067d37ba15e783c024088a09a.tar.gz
rust-f38d0da89389c45067d37ba15e783c024088a09a.zip
Implement optimize(size) and optimize(speed)
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/attributes.rs44
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs4
-rw-r--r--src/librustc_codegen_llvm/back/write.rs51
-rw-r--r--src/librustc_codegen_llvm/base.rs4
-rw-r--r--src/librustc_codegen_llvm/context.rs5
-rw-r--r--src/librustc_codegen_llvm/declare.rs21
-rw-r--r--src/librustc_codegen_llvm/lib.rs17
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs1
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs6
9 files changed, 99 insertions, 54 deletions
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 226b03c99c0..5a39e4f8b7f 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -5,7 +5,7 @@ use std::ffi::CString;
 use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::session::Session;
-use rustc::session::config::Sanitizer;
+use rustc::session::config::{Sanitizer, OptLevel};
 use rustc::ty::{self, TyCtxt, PolyFnSig};
 use rustc::ty::layout::HasTyCtxt;
 use rustc::ty::query::Providers;
@@ -20,7 +20,7 @@ use attributes;
 use llvm::{self, Attribute};
 use llvm::AttributePlace::Function;
 use llvm_util;
-pub use syntax::attr::{self, InlineAttr};
+pub use syntax::attr::{self, InlineAttr, OptimizeAttr};
 
 use context::CodegenCx;
 use value::Value;
@@ -57,13 +57,6 @@ fn unwind(val: &'ll Value, can_unwind: bool) {
     Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind);
 }
 
-/// Tell LLVM whether it should optimize function for size.
-#[inline]
-#[allow(dead_code)] // possibly useful function
-pub fn set_optimize_for_size(val: &'ll Value, optimize: bool) {
-    Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize);
-}
-
 /// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue.
 #[inline]
 pub fn naked(val: &'ll Value, is_naked: bool) {
@@ -164,6 +157,39 @@ pub fn from_fn_attrs(
 
     inline(cx, llfn, codegen_fn_attrs.inline);
 
+    match codegen_fn_attrs.optimize {
+        OptimizeAttr::None => {
+            match cx.tcx.sess.opts.optimize {
+                OptLevel::Size => {
+                    llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
+                    llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
+                    llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
+                },
+                OptLevel::SizeMin => {
+                    llvm::Attribute::MinSize.apply_llfn(Function, llfn);
+                    llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
+                    llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
+                }
+                OptLevel::No => {
+                    llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
+                    llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
+                    llvm::Attribute::OptimizeNone.apply_llfn(Function, llfn);
+                }
+                _ => {}
+            }
+        }
+        OptimizeAttr::Speed => {
+            llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
+            llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
+            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
+        }
+        OptimizeAttr::Size => {
+            llvm::Attribute::MinSize.apply_llfn(Function, llfn);
+            llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
+            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
+        }
+    }
+
     // The `uwtable` attribute according to LLVM is:
     //
     //     This attribute indicates that the ABI being targeted requires that an
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 5d5f1ceceb8..3e51078dc64 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -3,7 +3,7 @@ use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, pre_lto_bitcode_filename};
 use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinShared, ThinModule};
 use rustc_codegen_ssa::traits::*;
-use back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode, get_llvm_opt_level};
+use back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode, to_llvm_opt_settings};
 use errors::{FatalError, Handler};
 use llvm::archive_ro::ArchiveRO;
 use llvm::{self, True, False};
@@ -532,7 +532,7 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
         // Note that in general this shouldn't matter too much as you typically
         // only turn on ThinLTO when you're compiling with optimizations
         // otherwise.
-        let opt_level = config.opt_level.map(get_llvm_opt_level)
+        let opt_level = config.opt_level.map(|x| to_llvm_opt_settings(x).0)
             .unwrap_or(llvm::CodeGenOptLevel::None);
         let opt_level = match opt_level {
             llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index c0a4f5aa440..47637f3c5d7 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -5,8 +5,10 @@ use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler
 use rustc_codegen_ssa::traits::*;
 use base;
 use consts;
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::session::config::{self, OutputType, Passes, Lto};
 use rustc::session::Session;
+use rustc::ty::TyCtxt;
 use time_graph::Timeline;
 use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
 use llvm_util;
@@ -81,42 +83,46 @@ pub fn write_output_file(
     }
 }
 
-pub(crate) fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
-    match optimize {
-      config::OptLevel::No => llvm::CodeGenOptLevel::None,
-      config::OptLevel::Less => llvm::CodeGenOptLevel::Less,
-      config::OptLevel::Default => llvm::CodeGenOptLevel::Default,
-      config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive,
-      _ => llvm::CodeGenOptLevel::Default,
-    }
-}
-
-pub(crate) fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize {
-    match optimize {
-      config::OptLevel::Size => llvm::CodeGenOptSizeDefault,
-      config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive,
-      _ => llvm::CodeGenOptSizeNone,
-    }
+pub fn create_target_machine(
+    tcx: TyCtxt,
+    find_features: bool,
+) -> &'static mut llvm::TargetMachine {
+    target_machine_factory(tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE), find_features)()
+        .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise() )
 }
 
-pub fn create_target_machine(
+pub fn create_informational_target_machine(
     sess: &Session,
     find_features: bool,
 ) -> &'static mut llvm::TargetMachine {
-    target_machine_factory(sess, find_features)().unwrap_or_else(|err| {
+    target_machine_factory(sess, config::OptLevel::No, find_features)().unwrap_or_else(|err| {
         llvm_err(sess.diagnostic(), &err).raise()
     })
 }
 
+
+pub fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize)
+{
+    use self::config::OptLevel::*;
+    match cfg {
+        No => (llvm::CodeGenOptLevel::None, llvm::CodeGenOptSizeNone),
+        Less => (llvm::CodeGenOptLevel::Less, llvm::CodeGenOptSizeNone),
+        Default => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeNone),
+        Aggressive => (llvm::CodeGenOptLevel::Aggressive, llvm::CodeGenOptSizeNone),
+        Size => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeDefault),
+        SizeMin => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeAggressive),
+    }
+}
+
 // If find_features is true this won't access `sess.crate_types` by assuming
 // that `is_pie_binary` is false. When we discover LLVM target features
 // `sess.crate_types` is uninitialized so we cannot access it.
-pub fn target_machine_factory(sess: &Session, find_features: bool)
+pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_features: bool)
     -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync>
 {
     let reloc_model = get_reloc_model(sess);
 
-    let opt_level = get_llvm_opt_level(sess.opts.optimize);
+    let (opt_level, _) = to_llvm_opt_settings(optlvl);
     let use_softfp = sess.opts.cg.soft_float;
 
     let ffunction_sections = sess.target.target.options.function_sections;
@@ -357,7 +363,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
             if !config.no_prepopulate_passes {
                 llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
                 llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
-                let opt_level = config.opt_level.map(get_llvm_opt_level)
+                let opt_level = config.opt_level.map(|x| to_llvm_opt_settings(x).0)
                     .unwrap_or(llvm::CodeGenOptLevel::None);
                 let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal ||
                     (cgcx.lto != Lto::Fat && cgcx.opts.debugging_opts.cross_lang_lto.enabled());
@@ -689,7 +695,8 @@ pub unsafe fn with_llvm_pmb(llmod: &llvm::Module,
     // reasonable defaults and prepare it to actually populate the pass
     // manager.
     let builder = llvm::LLVMPassManagerBuilderCreate();
-    let opt_size = config.opt_size.map(get_llvm_opt_size).unwrap_or(llvm::CodeGenOptSizeNone);
+    let opt_size = config.opt_size.map(|x| to_llvm_opt_settings(x).1)
+        .unwrap_or(llvm::CodeGenOptSizeNone);
     let inline_threshold = config.inline_threshold;
 
     let pgo_gen_path = config.pgo_gen.as_ref().map(|s| {
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 6a0d5fa1e1f..6e1ef440a3f 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -136,7 +136,7 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
     }
 }
 
-pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>,
+pub fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   cgu_name: InternedString)
                                   -> Stats {
     let start_time = Instant::now();
@@ -164,7 +164,7 @@ pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>,
         let backend = LlvmCodegenBackend(());
         let cgu = tcx.codegen_unit(cgu_name);
         // Instantiate monomorphizations without filling out definitions yet...
-        let llvm_module = backend.new_metadata(tcx.sess, &cgu_name.as_str());
+        let llvm_module = backend.new_metadata(tcx, &cgu_name.as_str());
         let stats = {
             let cx = CodegenCx::new(tcx, cgu, &llvm_module);
             let mono_items = cx.codegen_unit
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 2b03e99161d..1d7f14b02e1 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -144,16 +144,17 @@ pub fn is_pie_binary(sess: &Session) -> bool {
 }
 
 pub unsafe fn create_module(
-    sess: &Session,
+    tcx: TyCtxt,
     llcx: &'ll llvm::Context,
     mod_name: &str,
 ) -> &'ll llvm::Module {
+    let sess = tcx.sess;
     let mod_name = SmallCStr::new(mod_name);
     let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
 
     // Ensure the data-layout values hardcoded remain the defaults.
     if sess.target.target.options.is_builtin {
-        let tm = ::back::write::create_target_machine(sess, false);
+        let tm = ::back::write::create_target_machine(tcx, false);
         llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
         llvm::LLVMRustDisposeTargetMachine(tm);
 
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index aa2a0016b3e..166c6ab9ae9 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -15,7 +15,7 @@ use llvm;
 use llvm::AttributePlace::Function;
 use rustc::ty::{self, PolyFnSig};
 use rustc::ty::layout::LayoutOf;
-use rustc::session::config::Sanitizer;
+use rustc::session::config::{Sanitizer, OptLevel};
 use rustc_data_structures::small_c_str::SmallCStr;
 use abi::{FnType, FnTypeExt};
 use attributes;
@@ -65,15 +65,24 @@ fn declare_raw_fn(
         }
     }
 
-    match cx.tcx.sess.opts.cg.opt_level.as_ref().map(String::as_ref) {
-        Some("s") => {
+    // FIXME(opt): this is kinda duplicated with similar code in attributes::from_fm_attrs…
+    match cx.tcx.sess.opts.optimize {
+        OptLevel::Size => {
+            llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
             llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
+            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
         },
-        Some("z") => {
+        OptLevel::SizeMin => {
             llvm::Attribute::MinSize.apply_llfn(Function, llfn);
             llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
-        },
-        _ => {},
+            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
+        }
+        OptLevel::No => {
+            llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
+            llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
+            llvm::Attribute::OptimizeNone.apply_llfn(Function, llfn);
+        }
+        _ => {}
     }
 
     attributes::non_lazy_bind(cx.sess(), llfn);
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 272f34b0b3f..662b84b3a91 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -73,7 +73,7 @@ use rustc::dep_graph::DepGraph;
 use rustc::middle::allocator::AllocatorKind;
 use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
 use rustc::session::{Session, CompileIncomplete};
-use rustc::session::config::{OutputFilenames, OutputType, PrintRequest};
+use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
 use rustc::ty::{self, TyCtxt};
 use rustc::util::time_graph;
 use rustc::util::profiling::ProfileCategory;
@@ -122,8 +122,8 @@ mod va_arg;
 pub struct LlvmCodegenBackend(());
 
 impl ExtraBackendMethods for LlvmCodegenBackend {
-    fn new_metadata(&self, sess: &Session, mod_name: &str) -> ModuleLlvm {
-        ModuleLlvm::new(sess, mod_name)
+    fn new_metadata(&self, tcx: TyCtxt, mod_name: &str) -> ModuleLlvm {
+        ModuleLlvm::new(tcx, mod_name)
     }
     fn write_metadata<'b, 'gcx>(
         &self,
@@ -145,10 +145,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
     fn target_machine_factory(
         &self,
         sess: &Session,
+        optlvl: OptLevel,
         find_features: bool
     ) -> Arc<dyn Fn() ->
         Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
-        back::write::target_machine_factory(sess, find_features)
+        back::write::target_machine_factory(sess, optlvl, find_features)
     }
     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
         llvm_util::target_cpu(sess)
@@ -364,15 +365,15 @@ unsafe impl Send for ModuleLlvm { }
 unsafe impl Sync for ModuleLlvm { }
 
 impl ModuleLlvm {
-    fn new(sess: &Session, mod_name: &str) -> Self {
+    fn new(tcx: TyCtxt, mod_name: &str) -> Self {
         unsafe {
-            let llcx = llvm::LLVMRustContextCreate(sess.fewer_names());
-            let llmod_raw = context::create_module(sess, llcx, mod_name) as *const _;
+            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
+            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
 
             ModuleLlvm {
                 llmod_raw,
                 llcx,
-                tm: create_target_machine(sess, false),
+                tm: create_target_machine(tcx, false),
             }
         }
     }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 11e34f600c2..fe2aed09ebc 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -115,6 +115,7 @@ pub enum Attribute {
     SanitizeAddress = 21,
     SanitizeMemory  = 22,
     NonLazyBind     = 23,
+    OptimizeNone    = 24,
 }
 
 /// LLVMIntPredicate
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index dc70ebcf943..e2d0e558d3b 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -1,5 +1,5 @@
 use syntax_pos::symbol::Symbol;
-use back::write::create_target_machine;
+use back::write::create_informational_target_machine;
 use llvm;
 use rustc::session::Session;
 use rustc::session::config::PrintRequest;
@@ -223,7 +223,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
 }
 
 pub fn target_features(sess: &Session) -> Vec<Symbol> {
-    let target_machine = create_target_machine(sess, true);
+    let target_machine = create_informational_target_machine(sess, true);
     target_feature_whitelist(sess)
         .iter()
         .filter_map(|&(feature, gate)| {
@@ -276,7 +276,7 @@ pub fn print_passes() {
 
 pub(crate) fn print(req: PrintRequest, sess: &Session) {
     require_inited();
-    let tm = create_target_machine(sess, true);
+    let tm = create_informational_target_machine(sess, true);
     unsafe {
         match req {
             PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),