X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_codegen_llvm%2Fattributes.rs;h=fc1b365cf90ce57cfbeaf1a54a3d8ea83e0df4c8;hb=29951edbdfcb3e65e689e43c997a98d8aad5e273;hp=3f2a51b45bd0645fbf56f1b9ff0d0b30a6e5f422;hpb=d7dc3502f9ad8f8ab0cc7f22388b92b2216f57fe;p=rust.git diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 3f2a51b45bd..fc1b365cf90 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -2,24 +2,24 @@ use std::ffi::CString; -use rustc::hir::CodegenFnAttrFlags; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc::session::config::{OptLevel, Sanitizer}; use rustc::session::Session; -use rustc::session::config::{Sanitizer, OptLevel}; -use rustc::ty::{self, TyCtxt, Ty}; use rustc::ty::layout::HasTyCtxt; use rustc::ty::query::Providers; -use rustc_data_structures::small_c_str::SmallCStr; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc_codegen_ssa::traits::*; +use rustc_data_structures::const_cstr; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::small_c_str::SmallCStr; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_target::abi::call::Conv; -use rustc_data_structures::const_cstr; use rustc_target::spec::PanicStrategy; -use rustc_codegen_ssa::traits::*; use crate::abi::FnAbi; use crate::attributes; -use crate::llvm::{self, Attribute}; use crate::llvm::AttributePlace::Function; +use crate::llvm::{self, Attribute}; use crate::llvm_util; pub use syntax::attr::{self, InlineAttr, OptimizeAttr}; @@ -31,18 +31,18 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { use self::InlineAttr::*; match inline { - Hint => Attribute::InlineHint.apply_llfn(Function, val), + Hint => Attribute::InlineHint.apply_llfn(Function, val), Always => Attribute::AlwaysInline.apply_llfn(Function, val), - Never => { + Never => { if cx.tcx().sess.target.target.arch != "amdgpu" { Attribute::NoInline.apply_llfn(Function, val); } - }, - None => { + } + None => { Attribute::InlineHint.unapply_llfn(Function, val); Attribute::AlwaysInline.unapply_llfn(Function, val); Attribute::NoInline.unapply_llfn(Function, val); - }, + } }; } @@ -66,9 +66,21 @@ fn naked(val: &'ll Value, is_naked: bool) { pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { if cx.sess().must_not_eliminate_frame_pointers() { - llvm::AddFunctionAttrStringValue( - llfn, llvm::AttributePlace::Function, - const_cstr!("no-frame-pointer-elim"), const_cstr!("true")); + if llvm_util::get_major_version() >= 8 { + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + const_cstr!("frame-pointer"), + const_cstr!("all"), + ); + } else { + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + const_cstr!("no-frame-pointer-elim"), + const_cstr!("true"), + ); + } } } @@ -81,12 +93,16 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // The function name varies on platforms. // See test/CodeGen/mcount.c in clang. - let mcount_name = CString::new( - cx.sess().target.target.options.target_mcount.as_str().as_bytes()).unwrap(); + let mcount_name = + CString::new(cx.sess().target.target.options.target_mcount.as_str().as_bytes()) + .unwrap(); llvm::AddFunctionAttrStringValue( - llfn, llvm::AttributePlace::Function, - const_cstr!("instrument-function-entry-inlined"), &mcount_name); + llfn, + llvm::AttributePlace::Function, + const_cstr!("instrument-function-entry-inlined"), + &mcount_name, + ); } } @@ -94,16 +110,15 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // Only use stack probes if the target specification indicates that we // should be using stack probes if !cx.sess().target.target.options.stack_probes { - return + return; } // Currently stack probes seem somewhat incompatible with the address // sanitizer and thread sanitizer. With asan we're already protected from // stack overflow anyway so we don't really need stack probes regardless. match cx.sess().opts.debugging_opts.sanitizer { - Some(Sanitizer::Address) | - Some(Sanitizer::Thread) => return, - _ => {}, + Some(Sanitizer::Address) | Some(Sanitizer::Thread) => return, + _ => {} } // probestack doesn't play nice either with `-C profile-generate`. @@ -119,17 +134,16 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // Flag our internal `__rust_probestack` function as the stack probe symbol. // This is defined in the `compiler-builtins` crate for each architecture. llvm::AddFunctionAttrStringValue( - llfn, llvm::AttributePlace::Function, - const_cstr!("probe-stack"), const_cstr!("__rust_probestack")); + llfn, + llvm::AttributePlace::Function, + const_cstr!("probe-stack"), + const_cstr!("__rust_probestack"), + ); } fn translate_obsolete_target_features(feature: &str) -> &str { - const LLVM9_FEATURE_CHANGES: &[(&str, &str)] = &[ - ("+fp-only-sp", "-fp64"), - ("-fp-only-sp", "+fp64"), - ("+d16", "-d32"), - ("-d16", "+d32"), - ]; + const LLVM9_FEATURE_CHANGES: &[(&str, &str)] = + &[("+fp-only-sp", "-fp64"), ("-fp-only-sp", "+fp64"), ("+d16", "-d32"), ("-d16", "+d32")]; if llvm_util::get_major_version() >= 9 { for &(old, new) in LLVM9_FEATURE_CHANGES { if feature == old { @@ -147,13 +161,19 @@ fn translate_obsolete_target_features(feature: &str) -> &str { } pub fn llvm_target_features(sess: &Session) -> impl Iterator { - const RUSTC_SPECIFIC_FEATURES: &[&str] = &[ - "crt-static", - ]; + const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"]; - let cmdline = sess.opts.cg.target_feature.split(',') + let cmdline = sess + .opts + .cg + .target_feature + .split(',') .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); - sess.target.target.options.features.split(',') + sess.target + .target + .options + .features + .split(',') .chain(cmdline) .filter(|l| !l.is_empty()) .map(translate_obsolete_target_features) @@ -162,10 +182,11 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator { pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess)); llvm::AddFunctionAttrStringValue( - llfn, - llvm::AttributePlace::Function, - const_cstr!("target-cpu"), - target_cpu.as_c_str()); + llfn, + llvm::AttributePlace::Function, + const_cstr!("target-cpu"), + target_cpu.as_c_str(), + ); } /// Sets the `NonLazyBind` LLVM attribute on a given function, @@ -183,7 +204,7 @@ pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) { 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); @@ -198,7 +219,6 @@ pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) { } } - /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`) /// attributes. pub fn from_fn_attrs( @@ -226,7 +246,7 @@ pub fn from_fn_attrs( } // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites). - if instance.def.is_inline(cx.tcx) { + if instance.def.requires_inline(cx.tcx) { inline(cx, llfn, attributes::InlineAttr::Hint); } @@ -248,8 +268,7 @@ pub fn from_fn_attrs( // // You can also find more info on why Windows is whitelisted here in: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 - if !cx.sess().no_landing_pads() || - cx.sess().target.target.options.requires_uwtable { + if !cx.sess().no_landing_pads() || cx.sess().target.target.options.requires_uwtable { attributes::emit_uwtable(llfn, true); } @@ -267,46 +286,48 @@ pub fn from_fn_attrs( naked(llfn, true); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { - Attribute::NoAlias.apply_llfn( - llvm::AttributePlace::ReturnValue, llfn); + Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); } - unwind(llfn, if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind { - // In panic=abort mode we assume nothing can unwind anywhere, so - // optimize based on this! - false - } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) { - // If a specific #[unwind] attribute is present, use that. - true - } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { - // Special attribute for allocator functions, which can't unwind. - false - } else { - if fn_abi.conv == Conv::Rust { - // Any Rust method (or `extern "Rust" fn` or `extern - // "rust-call" fn`) is explicitly allowed to unwind - // (unless it has no-unwind attribute, handled above). + unwind( + llfn, + if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind { + // In panic=abort mode we assume nothing can unwind anywhere, so + // optimize based on this! + false + } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) { + // If a specific #[unwind] attribute is present, use that. true - } else { - // Anything else is either: - // - // 1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or - // - // 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`). - // - // Foreign items (case 1) are assumed to not unwind; it is - // UB otherwise. (At least for now; see also - // rust-lang/rust#63909 and Rust RFC 2753.) - // - // Items defined in Rust with non-Rust ABIs (case 2) are also - // not supposed to unwind. Whether this should be enforced - // (versus stating it is UB) and *how* it would be enforced - // is currently under discussion; see rust-lang/rust#58794. - // - // In either case, we mark item as explicitly nounwind. + } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { + // Special attribute for allocator functions, which can't unwind. false - } - }); + } else { + if fn_abi.conv == Conv::Rust { + // Any Rust method (or `extern "Rust" fn` or `extern + // "rust-call" fn`) is explicitly allowed to unwind + // (unless it has no-unwind attribute, handled above). + true + } else { + // Anything else is either: + // + // 1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or + // + // 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`). + // + // Foreign items (case 1) are assumed to not unwind; it is + // UB otherwise. (At least for now; see also + // rust-lang/rust#63909 and Rust RFC 2753.) + // + // Items defined in Rust with non-Rust ABIs (case 2) are also + // not supposed to unwind. Whether this should be enforced + // (versus stating it is UB) and *how* it would be enforced + // is currently under discussion; see rust-lang/rust#58794. + // + // In either case, we mark item as explicitly nounwind. + false + } + }, + ); // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated @@ -315,22 +336,21 @@ pub fn from_fn_attrs( let features = llvm_target_features(cx.tcx.sess) .map(|s| s.to_string()) - .chain( - codegen_fn_attrs.target_features - .iter() - .map(|f| { - let feature = &f.as_str(); - format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) - }) - ) + .chain(codegen_fn_attrs.target_features.iter().map(|f| { + let feature = &f.as_str(); + format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + })) .collect::>() .join(","); if !features.is_empty() { let val = CString::new(features).unwrap(); llvm::AddFunctionAttrStringValue( - llfn, llvm::AttributePlace::Function, - const_cstr!("target-features"), &val); + llfn, + llvm::AttributePlace::Function, + const_cstr!("target-features"), + &val, + ); } // Note that currently the `wasm-import-module` doesn't do anything, but @@ -345,9 +365,8 @@ pub fn from_fn_attrs( &module, ); - let name = codegen_fn_attrs.link_name.unwrap_or_else(|| { - cx.tcx.item_name(instance.def_id()) - }); + let name = + codegen_fn_attrs.link_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id())); let name = CString::new(&name.as_str()[..]).unwrap(); llvm::AddFunctionAttrStringValue( llfn, @@ -365,14 +384,15 @@ pub fn provide(providers: &mut Providers<'_>) { if tcx.sess.opts.actually_rustdoc { // rustdoc needs to be able to document functions that use all the features, so // whitelist them all - tcx.arena.alloc(llvm_util::all_known_features() - .map(|(a, b)| (a.to_string(), b)) - .collect()) + tcx.arena + .alloc(llvm_util::all_known_features().map(|(a, b)| (a.to_string(), b)).collect()) } else { - tcx.arena.alloc(llvm_util::target_feature_whitelist(tcx.sess) - .iter() - .map(|&(a, b)| (a.to_string(), b)) - .collect()) + tcx.arena.alloc( + llvm_util::target_feature_whitelist(tcx.sess) + .iter() + .map(|&(a, b)| (a.to_string(), b)) + .collect(), + ) } }; @@ -386,15 +406,14 @@ pub fn provide_extern(providers: &mut Providers<'_>) { // `#[link(wasm_import_module = "...")]` for example. let native_libs = tcx.native_libraries(cnum); - let def_id_to_native_lib = native_libs.iter().filter_map(|lib| - lib.foreign_module.map(|id| (id, lib)) - ).collect::>(); + let def_id_to_native_lib = native_libs + .iter() + .filter_map(|lib| lib.foreign_module.map(|id| (id, lib))) + .collect::>(); let mut ret = FxHashMap::default(); for lib in tcx.foreign_modules(cnum).iter() { - let module = def_id_to_native_lib - .get(&lib.def_id) - .and_then(|s| s.wasm_import_module); + let module = def_id_to_native_lib.get(&lib.def_id).and_then(|s| s.wasm_import_module); let module = match module { Some(s) => s, None => continue, @@ -410,7 +429,5 @@ pub fn provide_extern(providers: &mut Providers<'_>) { } fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option { - tcx.wasm_import_module_map(id.krate) - .get(&id) - .map(|s| CString::new(&s[..]).unwrap()) + tcx.wasm_import_module_map(id.krate).get(&id).map(|s| CString::new(&s[..]).unwrap()) }