Skip to content

Commit c38b8a8

Browse files
committed
Auto merge of #94579 - tmiasko:target-features, r=nagisa
Always include global target features in function attributes This ensures that information about target features configured with `-C target-feature=...` or detected with `-C target-cpu=native` is retained for subsequent consumers of LLVM bitcode. This is crucial for linker plugin LTO, since this information is not conveyed to the plugin otherwise. <details><summary>Additional test case demonstrating the issue</summary> ```rust extern crate core; #[inline] #[target_feature(enable = "aes")] unsafe fn f(a: u128, b: u128) -> u128 { use core::arch::x86_64::*; use core::mem::transmute; transmute(_mm_aesenc_si128(transmute(a), transmute(b))) } pub fn g(a: u128, b: u128) -> u128 { unsafe { f(a, b) } } fn main() { let mut args = std::env::args(); let _ = args.next().unwrap(); let a: u128 = args.next().unwrap().parse().unwrap(); let b: u128 = args.next().unwrap().parse().unwrap(); println!("{}", g(a, b)); } ``` ```console $ rustc --edition=2021 a.rs -Clinker-plugin-lto -Clink-arg=-fuse-ld=lld -Ctarget-feature=+aes -O ... = note: LLVM ERROR: Cannot select: intrinsic %llvm.x86.aesni.aesenc ``` </details> r? `@nagisa`
2 parents a64180f + 095d818 commit c38b8a8

File tree

7 files changed

+101
-11
lines changed

7 files changed

+101
-11
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Set and unset common attributes on LLVM values.
22
33
use rustc_codegen_ssa::traits::*;
4+
use rustc_data_structures::small_str::SmallStr;
45
use rustc_hir::def_id::DefId;
56
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
67
use rustc_middle::ty::{self, TyCtxt};
@@ -377,13 +378,12 @@ pub fn from_fn_attrs<'ll, 'tcx>(
377378
}
378379
}
379380

380-
if !function_features.is_empty() {
381-
let global_features = cx.tcx.global_backend_features(()).iter().map(|s| &s[..]);
382-
let val = global_features
383-
.chain(function_features.iter().map(|s| &s[..]))
384-
.intersperse(",")
385-
.collect::<String>();
386-
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &val));
381+
let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
382+
let function_features = function_features.iter().map(|s| s.as_str());
383+
let target_features =
384+
global_features.chain(function_features).intersperse(",").collect::<SmallStr<1024>>();
385+
if !target_features.is_empty() {
386+
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
387387
}
388388

389389
attributes::apply_to_llfn(llfn, Function, &to_add);

compiler/rustc_data_structures/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ stable_deref_trait = "1.0.0"
2020
rayon = { version = "0.3.2", package = "rustc-rayon" }
2121
rayon-core = { version = "0.3.2", package = "rustc-rayon-core" }
2222
rustc-hash = "1.1.0"
23-
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
23+
smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] }
2424
rustc_index = { path = "../rustc_index", package = "rustc_index" }
2525
bitflags = "1.2.1"
2626
measureme = "10.0.0"

compiler/rustc_data_structures/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub mod obligation_forest;
8080
pub mod owning_ref;
8181
pub mod sip128;
8282
pub mod small_c_str;
83+
pub mod small_str;
8384
pub mod snapshot_map;
8485
pub mod stable_map;
8586
pub mod svh;

compiler/rustc_data_structures/src/small_c_str.rs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ impl SmallCStr {
6262
impl Deref for SmallCStr {
6363
type Target = ffi::CStr;
6464

65+
#[inline]
6566
fn deref(&self) -> &ffi::CStr {
6667
self.as_c_str()
6768
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use smallvec::SmallVec;
2+
3+
#[cfg(test)]
4+
mod tests;
5+
6+
/// Like SmallVec but for strings.
7+
#[derive(Default)]
8+
pub struct SmallStr<const N: usize>(SmallVec<[u8; N]>);
9+
10+
impl<const N: usize> SmallStr<N> {
11+
#[inline]
12+
pub fn new() -> Self {
13+
SmallStr(SmallVec::default())
14+
}
15+
16+
#[inline]
17+
pub fn push_str(&mut self, s: &str) {
18+
self.0.extend_from_slice(s.as_bytes());
19+
}
20+
21+
#[inline]
22+
pub fn empty(&self) -> bool {
23+
self.0.is_empty()
24+
}
25+
26+
#[inline]
27+
pub fn spilled(&self) -> bool {
28+
self.0.spilled()
29+
}
30+
31+
#[inline]
32+
pub fn as_str(&self) -> &str {
33+
unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
34+
}
35+
}
36+
37+
impl<const N: usize> std::ops::Deref for SmallStr<N> {
38+
type Target = str;
39+
40+
#[inline]
41+
fn deref(&self) -> &str {
42+
self.as_str()
43+
}
44+
}
45+
46+
impl<const N: usize, A: AsRef<str>> FromIterator<A> for SmallStr<N> {
47+
#[inline]
48+
fn from_iter<T>(iter: T) -> Self
49+
where
50+
T: IntoIterator<Item = A>,
51+
{
52+
let mut s = SmallStr::default();
53+
s.extend(iter);
54+
s
55+
}
56+
}
57+
58+
impl<const N: usize, A: AsRef<str>> Extend<A> for SmallStr<N> {
59+
#[inline]
60+
fn extend<T>(&mut self, iter: T)
61+
where
62+
T: IntoIterator<Item = A>,
63+
{
64+
for a in iter.into_iter() {
65+
self.push_str(a.as_ref());
66+
}
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use super::*;
2+
3+
#[test]
4+
fn empty() {
5+
let s = SmallStr::<1>::new();
6+
assert!(s.empty());
7+
assert_eq!("", s.as_str());
8+
assert!(!s.spilled());
9+
}
10+
11+
#[test]
12+
fn from_iter() {
13+
let s = ["aa", "bb", "cc"].iter().collect::<SmallStr<6>>();
14+
assert_eq!("aabbcc", s.as_str());
15+
assert!(!s.spilled());
16+
17+
let s = ["aa", "bb", "cc", "dd"].iter().collect::<SmallStr<6>>();
18+
assert_eq!("aabbccdd", s.as_str());
19+
assert!(s.spilled());
20+
}

src/test/codegen/target-feature-overrides.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub unsafe fn apple() -> u32 {
2929
peach()
3030
}
3131

32-
// target features same as global (not reflected or overriden in IR)
32+
// target features same as global
3333
#[no_mangle]
3434
pub unsafe fn banana() -> u32 {
3535
// CHECK-LABEL: @banana()
@@ -43,5 +43,5 @@ pub unsafe fn banana() -> u32 {
4343
// COMPAT-SAME: "target-features"="+avx2,+avx,+avx"
4444
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
4545
// CHECK: attributes [[BANANAATTRS]]
46-
// CHECK-NOT: target-features
47-
// CHECK-SAME: }
46+
// COMPAT-SAME: "target-features"="+avx2,+avx"
47+
// INCOMPAT-SAME: "target-features"="-avx2,-avx"

0 commit comments

Comments
 (0)