Skip to content

Commit f38d0da

Browse files
committed
Implement optimize(size) and optimize(speed)
1 parent 095b44c commit f38d0da

File tree

26 files changed

+259
-107
lines changed

26 files changed

+259
-107
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ define_dep_nodes!( <'tcx>
642642
[eval_always] CollectAndPartitionMonoItems,
643643
[] IsCodegenedItem(DefId),
644644
[] CodegenUnit(InternedString),
645+
[] BackendOptimizationLevel(CrateNum),
645646
[] CompileCodegenUnit(InternedString),
646647
[input] OutputFilenames,
647648
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),

src/librustc/hir/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use syntax::source_map::Spanned;
2121
use rustc_target::spec::abi::Abi;
2222
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
2323
use syntax::ast::{Attribute, Label, Lit, StrStyle, FloatTy, IntTy, UintTy};
24-
use syntax::attr::InlineAttr;
24+
use syntax::attr::{InlineAttr, OptimizeAttr};
2525
use syntax::ext::hygiene::SyntaxContext;
2626
use syntax::ptr::P;
2727
use syntax::symbol::{Symbol, keywords};
@@ -2416,6 +2416,8 @@ pub struct CodegenFnAttrs {
24162416
pub flags: CodegenFnAttrFlags,
24172417
/// Parsed representation of the `#[inline]` attribute
24182418
pub inline: InlineAttr,
2419+
/// Parsed representation of the `#[optimize]` attribute
2420+
pub optimize: OptimizeAttr,
24192421
/// The `#[export_name = "..."]` attribute, indicating a custom symbol a
24202422
/// function should be exported under
24212423
pub export_name: Option<Symbol>,
@@ -2476,6 +2478,7 @@ impl CodegenFnAttrs {
24762478
CodegenFnAttrs {
24772479
flags: CodegenFnAttrFlags::empty(),
24782480
inline: InlineAttr::None,
2481+
optimize: OptimizeAttr::None,
24792482
export_name: None,
24802483
link_name: None,
24812484
target_features: vec![],

src/librustc/ich/impls_hir.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,7 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
11591159
impl_stable_hash_for!(struct hir::CodegenFnAttrs {
11601160
flags,
11611161
inline,
1162+
optimize,
11621163
export_name,
11631164
link_name,
11641165
target_features,
@@ -1183,6 +1184,14 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
11831184
}
11841185
}
11851186

1187+
impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
1188+
fn hash_stable<W: StableHasherResult>(&self,
1189+
hcx: &mut StableHashingContext<'hir>,
1190+
hasher: &mut StableHasher<W>) {
1191+
mem::discriminant(self).hash_stable(hcx, hasher);
1192+
}
1193+
}
1194+
11861195
impl_stable_hash_for!(struct hir::Freevar {
11871196
def,
11881197
span

src/librustc/session/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ pub enum OptLevel {
5858
SizeMin, // -Oz
5959
}
6060

61+
impl_stable_hash_via_hash!(OptLevel);
62+
6163
/// This is what the `LtoCli` values get mapped to after resolving defaults and
6264
/// and taking other command line options into account.
6365
#[derive(Clone, Copy, PartialEq, Hash, Debug)]

src/librustc/ty/query/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> {
967967
}
968968
}
969969

970+
impl<'tcx> QueryDescription<'tcx> for queries::backend_optimization_level<'tcx> {
971+
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
972+
"optimization level used by backend".into()
973+
}
974+
}
975+
970976
macro_rules! impl_disk_cacheable_query(
971977
($query_name:ident, |$key:tt| $cond:expr) => {
972978
impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> {

src/librustc/ty/query/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use mir::mono::CodegenUnit;
2222
use mir;
2323
use mir::interpret::GlobalId;
2424
use session::{CompileResult, CrateDisambiguator};
25-
use session::config::{EntryFnType, OutputFilenames};
25+
use session::config::{EntryFnType, OutputFilenames, OptLevel};
2626
use traits::{self, Vtable};
2727
use traits::query::{
2828
CanonicalPredicateGoal, CanonicalProjectionGoal,
@@ -573,6 +573,7 @@ define_queries! { <'tcx>
573573
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
574574
[] fn is_codegened_item: IsCodegenedItem(DefId) -> bool,
575575
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
576+
[] fn backend_optimization_level: BackendOptimizationLevel(CrateNum) -> OptLevel,
576577
},
577578

578579
Other {

src/librustc/ty/query/plumbing.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
14101410
DepKind::UpstreamMonomorphizationsFor => {
14111411
force!(upstream_monomorphizations_for, def_id!());
14121412
}
1413+
DepKind::BackendOptimizationLevel => {
1414+
force!(backend_optimization_level, krate!());
1415+
}
14131416
}
14141417

14151418
true

src/librustc_codegen_llvm/attributes.rs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::ffi::CString;
55
use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs};
66
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
77
use rustc::session::Session;
8-
use rustc::session::config::Sanitizer;
8+
use rustc::session::config::{Sanitizer, OptLevel};
99
use rustc::ty::{self, TyCtxt, PolyFnSig};
1010
use rustc::ty::layout::HasTyCtxt;
1111
use rustc::ty::query::Providers;
@@ -20,7 +20,7 @@ use attributes;
2020
use llvm::{self, Attribute};
2121
use llvm::AttributePlace::Function;
2222
use llvm_util;
23-
pub use syntax::attr::{self, InlineAttr};
23+
pub use syntax::attr::{self, InlineAttr, OptimizeAttr};
2424

2525
use context::CodegenCx;
2626
use value::Value;
@@ -57,13 +57,6 @@ fn unwind(val: &'ll Value, can_unwind: bool) {
5757
Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind);
5858
}
5959

60-
/// Tell LLVM whether it should optimize function for size.
61-
#[inline]
62-
#[allow(dead_code)] // possibly useful function
63-
pub fn set_optimize_for_size(val: &'ll Value, optimize: bool) {
64-
Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize);
65-
}
66-
6760
/// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue.
6861
#[inline]
6962
pub fn naked(val: &'ll Value, is_naked: bool) {
@@ -164,6 +157,39 @@ pub fn from_fn_attrs(
164157

165158
inline(cx, llfn, codegen_fn_attrs.inline);
166159

160+
match codegen_fn_attrs.optimize {
161+
OptimizeAttr::None => {
162+
match cx.tcx.sess.opts.optimize {
163+
OptLevel::Size => {
164+
llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
165+
llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
166+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
167+
},
168+
OptLevel::SizeMin => {
169+
llvm::Attribute::MinSize.apply_llfn(Function, llfn);
170+
llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
171+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
172+
}
173+
OptLevel::No => {
174+
llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
175+
llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
176+
llvm::Attribute::OptimizeNone.apply_llfn(Function, llfn);
177+
}
178+
_ => {}
179+
}
180+
}
181+
OptimizeAttr::Speed => {
182+
llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
183+
llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
184+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
185+
}
186+
OptimizeAttr::Size => {
187+
llvm::Attribute::MinSize.apply_llfn(Function, llfn);
188+
llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
189+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
190+
}
191+
}
192+
167193
// The `uwtable` attribute according to LLVM is:
168194
//
169195
// This attribute indicates that the ABI being targeted requires that an

src/librustc_codegen_llvm/back/lto.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_codegen_ssa::back::symbol_export;
33
use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, pre_lto_bitcode_filename};
44
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinShared, ThinModule};
55
use rustc_codegen_ssa::traits::*;
6-
use back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode, get_llvm_opt_level};
6+
use back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode, to_llvm_opt_settings};
77
use errors::{FatalError, Handler};
88
use llvm::archive_ro::ArchiveRO;
99
use llvm::{self, True, False};
@@ -532,7 +532,7 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
532532
// Note that in general this shouldn't matter too much as you typically
533533
// only turn on ThinLTO when you're compiling with optimizations
534534
// otherwise.
535-
let opt_level = config.opt_level.map(get_llvm_opt_level)
535+
let opt_level = config.opt_level.map(|x| to_llvm_opt_settings(x).0)
536536
.unwrap_or(llvm::CodeGenOptLevel::None);
537537
let opt_level = match opt_level {
538538
llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,

src/librustc_codegen_llvm/back/write.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler
55
use rustc_codegen_ssa::traits::*;
66
use base;
77
use consts;
8+
use rustc::hir::def_id::LOCAL_CRATE;
89
use rustc::session::config::{self, OutputType, Passes, Lto};
910
use rustc::session::Session;
11+
use rustc::ty::TyCtxt;
1012
use time_graph::Timeline;
1113
use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
1214
use llvm_util;
@@ -81,42 +83,46 @@ pub fn write_output_file(
8183
}
8284
}
8385

84-
pub(crate) fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
85-
match optimize {
86-
config::OptLevel::No => llvm::CodeGenOptLevel::None,
87-
config::OptLevel::Less => llvm::CodeGenOptLevel::Less,
88-
config::OptLevel::Default => llvm::CodeGenOptLevel::Default,
89-
config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive,
90-
_ => llvm::CodeGenOptLevel::Default,
91-
}
92-
}
93-
94-
pub(crate) fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize {
95-
match optimize {
96-
config::OptLevel::Size => llvm::CodeGenOptSizeDefault,
97-
config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive,
98-
_ => llvm::CodeGenOptSizeNone,
99-
}
86+
pub fn create_target_machine(
87+
tcx: TyCtxt,
88+
find_features: bool,
89+
) -> &'static mut llvm::TargetMachine {
90+
target_machine_factory(tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE), find_features)()
91+
.unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise() )
10092
}
10193

102-
pub fn create_target_machine(
94+
pub fn create_informational_target_machine(
10395
sess: &Session,
10496
find_features: bool,
10597
) -> &'static mut llvm::TargetMachine {
106-
target_machine_factory(sess, find_features)().unwrap_or_else(|err| {
98+
target_machine_factory(sess, config::OptLevel::No, find_features)().unwrap_or_else(|err| {
10799
llvm_err(sess.diagnostic(), &err).raise()
108100
})
109101
}
110102

103+
104+
pub fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize)
105+
{
106+
use self::config::OptLevel::*;
107+
match cfg {
108+
No => (llvm::CodeGenOptLevel::None, llvm::CodeGenOptSizeNone),
109+
Less => (llvm::CodeGenOptLevel::Less, llvm::CodeGenOptSizeNone),
110+
Default => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeNone),
111+
Aggressive => (llvm::CodeGenOptLevel::Aggressive, llvm::CodeGenOptSizeNone),
112+
Size => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeDefault),
113+
SizeMin => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeAggressive),
114+
}
115+
}
116+
111117
// If find_features is true this won't access `sess.crate_types` by assuming
112118
// that `is_pie_binary` is false. When we discover LLVM target features
113119
// `sess.crate_types` is uninitialized so we cannot access it.
114-
pub fn target_machine_factory(sess: &Session, find_features: bool)
120+
pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_features: bool)
115121
-> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync>
116122
{
117123
let reloc_model = get_reloc_model(sess);
118124

119-
let opt_level = get_llvm_opt_level(sess.opts.optimize);
125+
let (opt_level, _) = to_llvm_opt_settings(optlvl);
120126
let use_softfp = sess.opts.cg.soft_float;
121127

122128
let ffunction_sections = sess.target.target.options.function_sections;
@@ -357,7 +363,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
357363
if !config.no_prepopulate_passes {
358364
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
359365
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
360-
let opt_level = config.opt_level.map(get_llvm_opt_level)
366+
let opt_level = config.opt_level.map(|x| to_llvm_opt_settings(x).0)
361367
.unwrap_or(llvm::CodeGenOptLevel::None);
362368
let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal ||
363369
(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,
689695
// reasonable defaults and prepare it to actually populate the pass
690696
// manager.
691697
let builder = llvm::LLVMPassManagerBuilderCreate();
692-
let opt_size = config.opt_size.map(get_llvm_opt_size).unwrap_or(llvm::CodeGenOptSizeNone);
698+
let opt_size = config.opt_size.map(|x| to_llvm_opt_settings(x).1)
699+
.unwrap_or(llvm::CodeGenOptSizeNone);
693700
let inline_threshold = config.inline_threshold;
694701

695702
let pgo_gen_path = config.pgo_gen.as_ref().map(|s| {

src/librustc_codegen_llvm/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
136136
}
137137
}
138138

139-
pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>,
139+
pub fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
140140
cgu_name: InternedString)
141141
-> Stats {
142142
let start_time = Instant::now();
@@ -164,7 +164,7 @@ pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>,
164164
let backend = LlvmCodegenBackend(());
165165
let cgu = tcx.codegen_unit(cgu_name);
166166
// Instantiate monomorphizations without filling out definitions yet...
167-
let llvm_module = backend.new_metadata(tcx.sess, &cgu_name.as_str());
167+
let llvm_module = backend.new_metadata(tcx, &cgu_name.as_str());
168168
let stats = {
169169
let cx = CodegenCx::new(tcx, cgu, &llvm_module);
170170
let mono_items = cx.codegen_unit

src/librustc_codegen_llvm/context.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,17 @@ pub fn is_pie_binary(sess: &Session) -> bool {
144144
}
145145

146146
pub unsafe fn create_module(
147-
sess: &Session,
147+
tcx: TyCtxt,
148148
llcx: &'ll llvm::Context,
149149
mod_name: &str,
150150
) -> &'ll llvm::Module {
151+
let sess = tcx.sess;
151152
let mod_name = SmallCStr::new(mod_name);
152153
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
153154

154155
// Ensure the data-layout values hardcoded remain the defaults.
155156
if sess.target.target.options.is_builtin {
156-
let tm = ::back::write::create_target_machine(sess, false);
157+
let tm = ::back::write::create_target_machine(tcx, false);
157158
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
158159
llvm::LLVMRustDisposeTargetMachine(tm);
159160

src/librustc_codegen_llvm/declare.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use llvm;
1515
use llvm::AttributePlace::Function;
1616
use rustc::ty::{self, PolyFnSig};
1717
use rustc::ty::layout::LayoutOf;
18-
use rustc::session::config::Sanitizer;
18+
use rustc::session::config::{Sanitizer, OptLevel};
1919
use rustc_data_structures::small_c_str::SmallCStr;
2020
use abi::{FnType, FnTypeExt};
2121
use attributes;
@@ -65,15 +65,24 @@ fn declare_raw_fn(
6565
}
6666
}
6767

68-
match cx.tcx.sess.opts.cg.opt_level.as_ref().map(String::as_ref) {
69-
Some("s") => {
68+
// FIXME(opt): this is kinda duplicated with similar code in attributes::from_fm_attrs…
69+
match cx.tcx.sess.opts.optimize {
70+
OptLevel::Size => {
71+
llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
7072
llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
73+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
7174
},
72-
Some("z") => {
75+
OptLevel::SizeMin => {
7376
llvm::Attribute::MinSize.apply_llfn(Function, llfn);
7477
llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
75-
},
76-
_ => {},
78+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
79+
}
80+
OptLevel::No => {
81+
llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
82+
llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
83+
llvm::Attribute::OptimizeNone.apply_llfn(Function, llfn);
84+
}
85+
_ => {}
7786
}
7887

7988
attributes::non_lazy_bind(cx.sess(), llfn);

0 commit comments

Comments
 (0)