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};
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);
- },
+ }
};
}
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"),
+ );
+ }
}
}
// 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,
+ );
}
}
// 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`.
// 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 {
}
pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
- 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)
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,
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);
}
}
-
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
/// attributes.
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);
}
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
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::<Vec<String>>()
.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
&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,
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(),
+ )
}
};
// `#[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::<FxHashMap<_, _>>();
+ let def_id_to_native_lib = native_libs
+ .iter()
+ .filter_map(|lib| lib.foreign_module.map(|id| (id, lib)))
+ .collect::<FxHashMap<_, _>>();
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,
}
fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<CString> {
- 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())
}