Implement optimize(size) and optimize(speed)
This commit is contained in:
parent
095b44c83b
commit
f38d0da893
26 changed files with 260 additions and 108 deletions
|
@ -642,6 +642,7 @@ define_dep_nodes!( <'tcx>
|
|||
[eval_always] CollectAndPartitionMonoItems,
|
||||
[] IsCodegenedItem(DefId),
|
||||
[] CodegenUnit(InternedString),
|
||||
[] BackendOptimizationLevel(CrateNum),
|
||||
[] CompileCodegenUnit(InternedString),
|
||||
[input] OutputFilenames,
|
||||
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
|
||||
|
|
|
@ -21,7 +21,7 @@ use syntax::source_map::Spanned;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
|
||||
use syntax::ast::{Attribute, Label, Lit, StrStyle, FloatTy, IntTy, UintTy};
|
||||
use syntax::attr::InlineAttr;
|
||||
use syntax::attr::{InlineAttr, OptimizeAttr};
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
|
@ -2416,6 +2416,8 @@ pub struct CodegenFnAttrs {
|
|||
pub flags: CodegenFnAttrFlags,
|
||||
/// Parsed representation of the `#[inline]` attribute
|
||||
pub inline: InlineAttr,
|
||||
/// Parsed representation of the `#[optimize]` attribute
|
||||
pub optimize: OptimizeAttr,
|
||||
/// The `#[export_name = "..."]` attribute, indicating a custom symbol a
|
||||
/// function should be exported under
|
||||
pub export_name: Option<Symbol>,
|
||||
|
@ -2476,6 +2478,7 @@ impl CodegenFnAttrs {
|
|||
CodegenFnAttrs {
|
||||
flags: CodegenFnAttrFlags::empty(),
|
||||
inline: InlineAttr::None,
|
||||
optimize: OptimizeAttr::None,
|
||||
export_name: None,
|
||||
link_name: None,
|
||||
target_features: vec![],
|
||||
|
|
|
@ -1159,6 +1159,7 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
|
|||
impl_stable_hash_for!(struct hir::CodegenFnAttrs {
|
||||
flags,
|
||||
inline,
|
||||
optimize,
|
||||
export_name,
|
||||
link_name,
|
||||
target_features,
|
||||
|
@ -1183,6 +1184,14 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'hir>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct hir::Freevar {
|
||||
def,
|
||||
span
|
||||
|
|
|
@ -58,6 +58,8 @@ pub enum OptLevel {
|
|||
SizeMin, // -Oz
|
||||
}
|
||||
|
||||
impl_stable_hash_via_hash!(OptLevel);
|
||||
|
||||
/// This is what the `LtoCli` values get mapped to after resolving defaults and
|
||||
/// and taking other command line options into account.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
|
|
|
@ -967,6 +967,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::backend_optimization_level<'tcx> {
|
||||
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
|
||||
"optimization level used by backend".into()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_disk_cacheable_query(
|
||||
($query_name:ident, |$key:tt| $cond:expr) => {
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> {
|
||||
|
|
|
@ -22,7 +22,7 @@ use mir::mono::CodegenUnit;
|
|||
use mir;
|
||||
use mir::interpret::GlobalId;
|
||||
use session::{CompileResult, CrateDisambiguator};
|
||||
use session::config::{EntryFnType, OutputFilenames};
|
||||
use session::config::{EntryFnType, OutputFilenames, OptLevel};
|
||||
use traits::{self, Vtable};
|
||||
use traits::query::{
|
||||
CanonicalPredicateGoal, CanonicalProjectionGoal,
|
||||
|
@ -573,6 +573,7 @@ define_queries! { <'tcx>
|
|||
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
|
||||
[] fn is_codegened_item: IsCodegenedItem(DefId) -> bool,
|
||||
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
|
||||
[] fn backend_optimization_level: BackendOptimizationLevel(CrateNum) -> OptLevel,
|
||||
},
|
||||
|
||||
Other {
|
||||
|
|
|
@ -1410,6 +1410,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
|||
DepKind::UpstreamMonomorphizationsFor => {
|
||||
force!(upstream_monomorphizations_for, def_id!());
|
||||
}
|
||||
DepKind::BackendOptimizationLevel => {
|
||||
force!(backend_optimization_level, krate!());
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_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| {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ pub enum Attribute {
|
|||
SanitizeAddress = 21,
|
||||
SanitizeMemory = 22,
|
||||
NonLazyBind = 23,
|
||||
OptimizeNone = 24,
|
||||
}
|
||||
|
||||
/// LLVMIntPredicate
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -982,6 +982,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
None
|
||||
};
|
||||
|
||||
let ol = tcx.backend_optimization_level(LOCAL_CRATE);
|
||||
let cgcx = CodegenContext::<B> {
|
||||
backend: backend.clone(),
|
||||
crate_types: sess.crate_types.borrow().clone(),
|
||||
|
@ -1005,7 +1006,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
regular_module_config: modules_config,
|
||||
metadata_module_config: metadata_config,
|
||||
allocator_module_config: allocator_config,
|
||||
tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, false)),
|
||||
tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol, false)),
|
||||
total_cgus,
|
||||
msvc_imps_needed: msvc_imps_needed(tcx),
|
||||
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
|
||||
|
|
|
@ -551,7 +551,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
&["crate"],
|
||||
Some("metadata")).as_str()
|
||||
.to_string();
|
||||
let metadata_llvm_module = backend.new_metadata(tcx.sess, &metadata_cgu_name);
|
||||
let metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
|
||||
let metadata = time(tcx.sess, "write metadata", || {
|
||||
backend.write_metadata(tcx, &metadata_llvm_module)
|
||||
});
|
||||
|
@ -636,7 +636,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
&["crate"],
|
||||
Some("allocator")).as_str()
|
||||
.to_string();
|
||||
let modules = backend.new_metadata(tcx.sess, &llmod_id);
|
||||
let modules = backend.new_metadata(tcx, &llmod_id);
|
||||
time(tcx.sess, "write allocator module", || {
|
||||
backend.codegen_allocator(tcx, &modules, kind)
|
||||
});
|
||||
|
@ -897,6 +897,39 @@ fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool {
|
|||
}
|
||||
|
||||
pub fn provide_both(providers: &mut Providers) {
|
||||
providers.backend_optimization_level = |tcx, cratenum| {
|
||||
let for_speed = match tcx.sess.opts.optimize {
|
||||
// If globally no optimisation is done, #[optimize] has no effect.
|
||||
//
|
||||
// This is done because if we ended up "upgrading" to `-O2` here, we’d populate the
|
||||
// pass manager and it is likely that some module-wide passes (such as inliner or
|
||||
// cross-function constant propagation) would ignore the `optnone` annotation we put
|
||||
// on the functions, thus necessarily involving these functions into optimisations.
|
||||
config::OptLevel::No => return config::OptLevel::No,
|
||||
// If globally optimise-speed is already specified, just use that level.
|
||||
config::OptLevel::Less => return config::OptLevel::Less,
|
||||
config::OptLevel::Default => return config::OptLevel::Default,
|
||||
config::OptLevel::Aggressive => return config::OptLevel::Aggressive,
|
||||
// If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
|
||||
// are present).
|
||||
config::OptLevel::Size => config::OptLevel::Default,
|
||||
config::OptLevel::SizeMin => config::OptLevel::Default,
|
||||
};
|
||||
|
||||
let (defids, _) = tcx.collect_and_partition_mono_items(cratenum);
|
||||
for id in &*defids {
|
||||
let hir::CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
|
||||
match optimize {
|
||||
attr::OptimizeAttr::None => continue,
|
||||
attr::OptimizeAttr::Size => continue,
|
||||
attr::OptimizeAttr::Speed => {
|
||||
return for_speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tcx.sess.opts.optimize;
|
||||
};
|
||||
|
||||
providers.dllimport_foreign_items = |tcx, krate| {
|
||||
let module_map = tcx.foreign_modules(krate);
|
||||
let module_map = module_map.iter()
|
||||
|
|
|
@ -6,7 +6,7 @@ use super::CodegenObject;
|
|||
use rustc::middle::allocator::AllocatorKind;
|
||||
use rustc::middle::cstore::EncodedMetadata;
|
||||
use rustc::mir::mono::Stats;
|
||||
use rustc::session::Session;
|
||||
use rustc::session::{Session, config};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||
use std::sync::Arc;
|
||||
|
@ -32,7 +32,7 @@ impl<'tcx, T> Backend<'tcx> for T where
|
|||
}
|
||||
|
||||
pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
|
||||
fn new_metadata(&self, sess: &Session, mod_name: &str) -> Self::Module;
|
||||
fn new_metadata(&self, sess: TyCtxt, mod_name: &str) -> Self::Module;
|
||||
fn write_metadata<'b, 'gcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'b, 'gcx, 'gcx>,
|
||||
|
@ -50,6 +50,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
|
|||
fn target_machine_factory(
|
||||
&self,
|
||||
sess: &Session,
|
||||
opt_level: config::OptLevel,
|
||||
find_features: bool,
|
||||
) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>;
|
||||
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
|
||||
|
|
|
@ -36,7 +36,7 @@ use rustc_target::spec::abi;
|
|||
|
||||
use syntax::ast;
|
||||
use syntax::ast::{Ident, MetaItemKind};
|
||||
use syntax::attr::{InlineAttr, list_contains_name, mark_used};
|
||||
use syntax::attr::{InlineAttr, OptimizeAttr, list_contains_name, mark_used};
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::feature_gate;
|
||||
use syntax::symbol::{keywords, Symbol};
|
||||
|
@ -2286,49 +2286,6 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
|
|||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
|
||||
} else if attr.check_name("thread_local") {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
|
||||
} else if attr.check_name("inline") {
|
||||
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
||||
if attr.path != "inline" {
|
||||
return ia;
|
||||
}
|
||||
let meta = match attr.meta() {
|
||||
Some(meta) => meta.node,
|
||||
None => return ia,
|
||||
};
|
||||
match meta {
|
||||
MetaItemKind::Word => {
|
||||
mark_used(attr);
|
||||
InlineAttr::Hint
|
||||
}
|
||||
MetaItemKind::List(ref items) => {
|
||||
mark_used(attr);
|
||||
inline_span = Some(attr.span);
|
||||
if items.len() != 1 {
|
||||
span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0534,
|
||||
"expected one argument"
|
||||
);
|
||||
InlineAttr::None
|
||||
} else if list_contains_name(&items[..], "always") {
|
||||
InlineAttr::Always
|
||||
} else if list_contains_name(&items[..], "never") {
|
||||
InlineAttr::Never
|
||||
} else {
|
||||
span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
items[0].span,
|
||||
E0535,
|
||||
"invalid argument"
|
||||
);
|
||||
|
||||
InlineAttr::None
|
||||
}
|
||||
}
|
||||
_ => ia,
|
||||
}
|
||||
});
|
||||
} else if attr.check_name("export_name") {
|
||||
if let Some(s) = attr.value_str() {
|
||||
if s.as_str().contains("\0") {
|
||||
|
@ -2378,6 +2335,76 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
|
|||
}
|
||||
}
|
||||
|
||||
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
||||
if attr.path != "inline" {
|
||||
return ia;
|
||||
}
|
||||
match attr.meta().map(|i| i.node) {
|
||||
Some(MetaItemKind::Word) => {
|
||||
mark_used(attr);
|
||||
InlineAttr::Hint
|
||||
}
|
||||
Some(MetaItemKind::List(ref items)) => {
|
||||
mark_used(attr);
|
||||
inline_span = Some(attr.span);
|
||||
if items.len() != 1 {
|
||||
span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0534,
|
||||
"expected one argument"
|
||||
);
|
||||
InlineAttr::None
|
||||
} else if list_contains_name(&items[..], "always") {
|
||||
InlineAttr::Always
|
||||
} else if list_contains_name(&items[..], "never") {
|
||||
InlineAttr::Never
|
||||
} else {
|
||||
span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
items[0].span,
|
||||
E0535,
|
||||
"invalid argument"
|
||||
);
|
||||
|
||||
InlineAttr::None
|
||||
}
|
||||
}
|
||||
Some(MetaItemKind::NameValue(_)) => ia,
|
||||
None => ia,
|
||||
}
|
||||
});
|
||||
|
||||
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
|
||||
if attr.path != "optimize" {
|
||||
return ia;
|
||||
}
|
||||
let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0720, "{}", s);
|
||||
match attr.meta().map(|i| i.node) {
|
||||
Some(MetaItemKind::Word) => {
|
||||
err(attr.span, "expected one argument");
|
||||
ia
|
||||
}
|
||||
Some(MetaItemKind::List(ref items)) => {
|
||||
mark_used(attr);
|
||||
inline_span = Some(attr.span);
|
||||
if items.len() != 1 {
|
||||
err(attr.span, "expected one argument");
|
||||
OptimizeAttr::None
|
||||
} else if list_contains_name(&items[..], "size") {
|
||||
OptimizeAttr::Size
|
||||
} else if list_contains_name(&items[..], "speed") {
|
||||
OptimizeAttr::Speed
|
||||
} else {
|
||||
err(items[0].span, "invalid argument");
|
||||
OptimizeAttr::None
|
||||
}
|
||||
}
|
||||
Some(MetaItemKind::NameValue(_)) => ia,
|
||||
None => ia,
|
||||
}
|
||||
});
|
||||
|
||||
// If a function uses #[target_feature] it can't be inlined into general
|
||||
// purpose functions as they wouldn't have the right target features
|
||||
// enabled. For that reason we also forbid #[inline(always)] as it can't be
|
||||
|
|
|
@ -4719,4 +4719,5 @@ register_diagnostics! {
|
|||
E0645, // trait aliases not finished
|
||||
E0698, // type inside generator must be known in this context
|
||||
E0719, // duplicate values for associated type binding
|
||||
E0720, // Malformed #[optimize] attribute
|
||||
}
|
||||
|
|
|
@ -63,6 +63,13 @@ pub enum InlineAttr {
|
|||
Never,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum OptimizeAttr {
|
||||
None,
|
||||
Speed,
|
||||
Size,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum UnwindAttr {
|
||||
Allowed,
|
||||
|
|
|
@ -4,8 +4,8 @@ mod builtin;
|
|||
|
||||
pub use self::builtin::{
|
||||
cfg_matches, contains_feature_attr, eval_condition, find_crate_name, find_deprecation,
|
||||
find_repr_attrs, find_stability, find_unwind_attr, Deprecation, InlineAttr, IntType, ReprAttr,
|
||||
RustcDeprecation, Stability, StabilityLevel, UnwindAttr,
|
||||
find_repr_attrs, find_stability, find_unwind_attr, Deprecation, InlineAttr, OptimizeAttr,
|
||||
IntType, ReprAttr, RustcDeprecation, Stability, StabilityLevel, UnwindAttr,
|
||||
};
|
||||
pub use self::IntType::*;
|
||||
pub use self::ReprAttr::*;
|
||||
|
|
|
@ -462,6 +462,9 @@ declare_features! (
|
|||
|
||||
// Re-Rebalance coherence
|
||||
(active, re_rebalance_coherence, "1.32.0", Some(55437), None),
|
||||
|
||||
// #[optimize(X)]
|
||||
(active, optimize_attribute, "1.34.0", Some(54882), None),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
@ -1215,6 +1218,12 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
|
|||
"#[alloc_error_handler] is an unstable feature",
|
||||
cfg_fn!(alloc_error_handler))),
|
||||
|
||||
// RFC 2412
|
||||
("optimize", Whitelisted, Gated(Stability::Unstable,
|
||||
"optimize_attribute",
|
||||
"#[optimize] attribute is an unstable feature",
|
||||
cfg_fn!(optimize_attribute))),
|
||||
|
||||
// Crate level attributes
|
||||
("crate_name", CrateLevel, template!(NameValueStr: "name"), Ungated),
|
||||
("crate_type", CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated),
|
||||
|
|
|
@ -188,6 +188,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
|
|||
return Attribute::SanitizeMemory;
|
||||
case NonLazyBind:
|
||||
return Attribute::NonLazyBind;
|
||||
case OptimizeNone:
|
||||
return Attribute::OptimizeNone;
|
||||
}
|
||||
report_fatal_error("bad AttributeKind");
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ enum LLVMRustAttribute {
|
|||
SanitizeAddress = 21,
|
||||
SanitizeMemory = 22,
|
||||
NonLazyBind = 23,
|
||||
OptimizeNone = 24,
|
||||
};
|
||||
|
||||
typedef struct OpaqueRustString *RustStringRef;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue