Implement optimize(size) and optimize(speed)
This commit is contained in:
parent
095b44c83b
commit
f38d0da893
26 changed files with 260 additions and 108 deletions
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue