diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 6fd836946ff..101da0012cb 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -1,6 +1,7 @@ //! Set and unset common attributes on LLVM values. use rustc_codegen_ssa::traits::*; +use rustc_data_structures::small_str::SmallStr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::{self, TyCtxt}; @@ -377,13 +378,12 @@ pub fn from_fn_attrs<'ll, 'tcx>( } } - if !function_features.is_empty() { - let global_features = cx.tcx.global_backend_features(()).iter().map(|s| &s[..]); - let val = global_features - .chain(function_features.iter().map(|s| &s[..])) - .intersperse(",") - .collect::(); - to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &val)); + let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str()); + let function_features = function_features.iter().map(|s| s.as_str()); + let target_features = + global_features.chain(function_features).intersperse(",").collect::>(); + if !target_features.is_empty() { + to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features)); } attributes::apply_to_llfn(llfn, Function, &to_add); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index ad296c97659..b82e9717261 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -20,7 +20,7 @@ stable_deref_trait = "1.0.0" rayon = { version = "0.3.2", package = "rustc-rayon" } rayon-core = { version = "0.3.2", package = "rustc-rayon-core" } rustc-hash = "1.1.0" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] } rustc_index = { path = "../rustc_index", package = "rustc_index" } bitflags = "1.2.1" measureme = "10.0.0" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index b1e59d65029..1a3fe652521 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -80,6 +80,7 @@ macro_rules! unlikely { pub mod owning_ref; pub mod sip128; pub mod small_c_str; +pub mod small_str; pub mod snapshot_map; pub mod stable_map; pub mod svh; diff --git a/compiler/rustc_data_structures/src/small_c_str.rs b/compiler/rustc_data_structures/src/small_c_str.rs index cd902524562..3a8ab8ff991 100644 --- a/compiler/rustc_data_structures/src/small_c_str.rs +++ b/compiler/rustc_data_structures/src/small_c_str.rs @@ -62,6 +62,7 @@ pub fn spilled(&self) -> bool { impl Deref for SmallCStr { type Target = ffi::CStr; + #[inline] fn deref(&self) -> &ffi::CStr { self.as_c_str() } diff --git a/compiler/rustc_data_structures/src/small_str.rs b/compiler/rustc_data_structures/src/small_str.rs new file mode 100644 index 00000000000..800acb1b03e --- /dev/null +++ b/compiler/rustc_data_structures/src/small_str.rs @@ -0,0 +1,68 @@ +use smallvec::SmallVec; + +#[cfg(test)] +mod tests; + +/// Like SmallVec but for strings. +#[derive(Default)] +pub struct SmallStr(SmallVec<[u8; N]>); + +impl SmallStr { + #[inline] + pub fn new() -> Self { + SmallStr(SmallVec::default()) + } + + #[inline] + pub fn push_str(&mut self, s: &str) { + self.0.extend_from_slice(s.as_bytes()); + } + + #[inline] + pub fn empty(&self) -> bool { + self.0.is_empty() + } + + #[inline] + pub fn spilled(&self) -> bool { + self.0.spilled() + } + + #[inline] + pub fn as_str(&self) -> &str { + unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) } + } +} + +impl std::ops::Deref for SmallStr { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.as_str() + } +} + +impl> FromIterator for SmallStr { + #[inline] + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + let mut s = SmallStr::default(); + s.extend(iter); + s + } +} + +impl> Extend for SmallStr { + #[inline] + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + for a in iter.into_iter() { + self.push_str(a.as_ref()); + } + } +} diff --git a/compiler/rustc_data_structures/src/small_str/tests.rs b/compiler/rustc_data_structures/src/small_str/tests.rs new file mode 100644 index 00000000000..7635a9b7204 --- /dev/null +++ b/compiler/rustc_data_structures/src/small_str/tests.rs @@ -0,0 +1,20 @@ +use super::*; + +#[test] +fn empty() { + let s = SmallStr::<1>::new(); + assert!(s.empty()); + assert_eq!("", s.as_str()); + assert!(!s.spilled()); +} + +#[test] +fn from_iter() { + let s = ["aa", "bb", "cc"].iter().collect::>(); + assert_eq!("aabbcc", s.as_str()); + assert!(!s.spilled()); + + let s = ["aa", "bb", "cc", "dd"].iter().collect::>(); + assert_eq!("aabbccdd", s.as_str()); + assert!(s.spilled()); +} diff --git a/src/test/codegen/target-feature-overrides.rs b/src/test/codegen/target-feature-overrides.rs index 2c19cfd8c22..4be77e36e76 100644 --- a/src/test/codegen/target-feature-overrides.rs +++ b/src/test/codegen/target-feature-overrides.rs @@ -29,7 +29,7 @@ pub unsafe fn apple() -> u32 { peach() } -// target features same as global (not reflected or overriden in IR) +// target features same as global #[no_mangle] pub unsafe fn banana() -> u32 { // CHECK-LABEL: @banana() @@ -43,5 +43,5 @@ pub unsafe fn banana() -> u32 { // COMPAT-SAME: "target-features"="+avx2,+avx,+avx" // INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx" // CHECK: attributes [[BANANAATTRS]] -// CHECK-NOT: target-features -// CHECK-SAME: } +// COMPAT-SAME: "target-features"="+avx2,+avx" +// INCOMPAT-SAME: "target-features"="-avx2,-avx"