Auto merge of #95223 - Dylan-DPC:rollup-idpb7ka, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #91608 (Fold aarch64 feature +fp into +neon) - #92955 (add perf side effect docs to `Iterator::cloned()`) - #94713 (Add u16::is_utf16_surrogate) - #95212 (Replace `this.clone()` with `this.create_snapshot_for_diagnostic()`) - #95219 (Modernize `alloc-no-oom-handling` test) - #95222 (interpret/validity: improve clarity) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7b0bf9efc9
16 changed files with 206 additions and 21 deletions
|
@ -187,7 +187,6 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
|
|||
("x86", "avx512vaes") => smallvec!["vaes"],
|
||||
("x86", "avx512gfni") => smallvec!["gfni"],
|
||||
("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
|
||||
("aarch64", "fp") => smallvec!["fp-armv8"],
|
||||
("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
|
||||
("aarch64", "dpb") => smallvec!["ccpp"],
|
||||
("aarch64", "dpb2") => smallvec!["ccdp"],
|
||||
|
@ -230,6 +229,8 @@ pub fn check_tied_features(
|
|||
None
|
||||
}
|
||||
|
||||
// Used to generate cfg variables and apply features
|
||||
// Must express features in the way Rust understands them
|
||||
pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
||||
let target_machine = create_informational_target_machine(sess);
|
||||
let mut features: Vec<Symbol> =
|
||||
|
@ -239,13 +240,14 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
|||
if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
|
||||
})
|
||||
.filter(|feature| {
|
||||
// check that all features in a given smallvec are enabled
|
||||
for llvm_feature in to_llvm_features(sess, feature) {
|
||||
let cstr = SmallCStr::new(llvm_feature);
|
||||
if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
|
||||
return true;
|
||||
if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
false
|
||||
true
|
||||
})
|
||||
.map(|feature| Symbol::intern(feature))
|
||||
.collect();
|
||||
|
|
|
@ -43,10 +43,8 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
|||
];
|
||||
|
||||
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
// FEAT_AdvSimd
|
||||
// FEAT_AdvSimd & FEAT_FP
|
||||
("neon", None),
|
||||
// FEAT_FP
|
||||
("fp", None),
|
||||
// FEAT_FP16
|
||||
("fp16", None),
|
||||
// FEAT_SVE
|
||||
|
@ -143,7 +141,6 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
|||
];
|
||||
|
||||
const AARCH64_TIED_FEATURES: &[&[&str]] = &[
|
||||
&["fp", "neon"], // Silicon always has both, so avoid needless complications
|
||||
&["paca", "pacg"], // Together these represent `pauth` in LLVM
|
||||
];
|
||||
|
||||
|
|
|
@ -432,9 +432,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
if let Some(ref mut ref_tracking) = self.ref_tracking {
|
||||
// Proceed recursively even for ZST, no reason to skip them!
|
||||
// `!` is a ZST and we want to validate it.
|
||||
// Skip validation entirely for some external statics
|
||||
if let Ok((alloc_id, _offset, _ptr)) = self.ecx.memory.ptr_try_get_alloc(place.ptr) {
|
||||
// not a ZST
|
||||
// Special handling for pointers to statics (irrespective of their type).
|
||||
let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id);
|
||||
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
|
||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||
|
@ -469,7 +468,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// We need to clone the path anyway, make sure it gets created
|
||||
// with enough space for the additional `Deref`.
|
||||
let mut new_path = Vec::with_capacity(path.len() + 1);
|
||||
new_path.clone_from(path);
|
||||
new_path.extend(path);
|
||||
new_path.push(PathElem::Deref);
|
||||
new_path
|
||||
});
|
||||
|
|
|
@ -118,7 +118,7 @@ impl<'a> Parser<'a> {
|
|||
Some(this.parse_ty_param(attrs)?)
|
||||
} else if this.token.can_begin_type() {
|
||||
// Trying to write an associated type bound? (#26271)
|
||||
let snapshot = this.clone();
|
||||
let snapshot = this.create_snapshot_for_diagnostic();
|
||||
match this.parse_ty_where_predicate() {
|
||||
Ok(where_predicate) => {
|
||||
this.struct_span_err(
|
||||
|
@ -133,7 +133,7 @@ impl<'a> Parser<'a> {
|
|||
Err(err) => {
|
||||
err.cancel();
|
||||
// FIXME - maybe we should overwrite 'self' outside of `collect_tokens`?
|
||||
*this = snapshot;
|
||||
this.restore_snapshot(snapshot);
|
||||
return Ok((None, TrailingToken::None));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ impl AArch64InlineAsmRegClass {
|
|||
match self {
|
||||
Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
|
||||
Self::vreg | Self::vreg_low16 => types! {
|
||||
fp: I8, I16, I32, I64, F32, F64,
|
||||
neon: I8, I16, I32, I64, F32, F64,
|
||||
VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
|
||||
},
|
||||
|
|
|
@ -91,7 +91,7 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> {
|
|||
None => self.iter.next()?,
|
||||
};
|
||||
|
||||
if u < 0xD800 || 0xDFFF < u {
|
||||
if !u.is_utf16_surrogate() {
|
||||
// SAFETY: not a surrogate
|
||||
Some(Ok(unsafe { from_u32_unchecked(u as u32) }))
|
||||
} else if u >= 0xDC00 {
|
||||
|
@ -125,7 +125,7 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> {
|
|||
// buf is empty, no additional elements from it.
|
||||
None => (0, 0),
|
||||
// `u` is a non surrogate, so it's always an additional character.
|
||||
Some(u) if u < 0xD800 || 0xDFFF < u => (1, 1),
|
||||
Some(u) if !u.is_utf16_surrogate() => (1, 1),
|
||||
// `u` is a leading surrogate (it can never be a trailing surrogate and
|
||||
// it's a surrogate due to the previous branch) and `self.iter` is empty.
|
||||
//
|
||||
|
|
|
@ -3189,6 +3189,10 @@ pub trait Iterator {
|
|||
/// This is useful when you have an iterator over `&T`, but you need an
|
||||
/// iterator over `T`.
|
||||
///
|
||||
/// There is no guarantee whatsoever about the `clone` method actually
|
||||
/// being called *or* optimized away. So code should not depend on
|
||||
/// either.
|
||||
///
|
||||
/// [`clone`]: Clone::clone
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -3206,6 +3210,18 @@ pub trait Iterator {
|
|||
/// assert_eq!(v_cloned, vec![1, 2, 3]);
|
||||
/// assert_eq!(v_map, vec![1, 2, 3]);
|
||||
/// ```
|
||||
///
|
||||
/// To get the best performance, try to clone late:
|
||||
///
|
||||
/// ```
|
||||
/// let a = [vec![0_u8, 1, 2], vec![3, 4], vec![23]];
|
||||
/// // don't do this:
|
||||
/// let slower: Vec<_> = a.iter().cloned().filter(|s| s.len() == 1).collect();
|
||||
/// assert_eq!(&[vec![23]], &slower[..]);
|
||||
/// // instead call `cloned` late
|
||||
/// let faster: Vec<_> = a.iter().filter(|s| s.len() == 1).cloned().collect();
|
||||
/// assert_eq!(&[vec![23]], &faster[..]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn cloned<'a, T: 'a>(self) -> Cloned<Self>
|
||||
where
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
#![warn(missing_docs)]
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
//
|
||||
// Library features for const fns:
|
||||
// Library features:
|
||||
#![feature(const_align_offset)]
|
||||
#![feature(const_align_of_val)]
|
||||
#![feature(const_alloc_layout)]
|
||||
|
@ -146,6 +146,8 @@
|
|||
#![feature(ptr_metadata)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(utf16_extra)]
|
||||
#![feature(utf16_extra_const)]
|
||||
#![feature(variant_count)]
|
||||
#![feature(const_array_from_ref)]
|
||||
#![feature(const_slice_from_ref)]
|
||||
|
|
|
@ -820,6 +820,31 @@ impl u16 {
|
|||
uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
|
||||
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
|
||||
widening_impl! { u16, u32, 16, unsigned }
|
||||
|
||||
/// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(utf16_extra)]
|
||||
///
|
||||
/// let low_non_surrogate = 0xA000u16;
|
||||
/// let low_surrogate = 0xD800u16;
|
||||
/// let high_surrogate = 0xDC00u16;
|
||||
/// let high_non_surrogate = 0xE000u16;
|
||||
///
|
||||
/// assert!(!low_non_surrogate.is_utf16_surrogate());
|
||||
/// assert!(low_surrogate.is_utf16_surrogate());
|
||||
/// assert!(high_surrogate.is_utf16_surrogate());
|
||||
/// assert!(!high_non_surrogate.is_utf16_surrogate());
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "utf16_extra", issue = "94919")]
|
||||
#[rustc_const_unstable(feature = "utf16_extra_const", issue = "94919")]
|
||||
#[inline]
|
||||
pub const fn is_utf16_surrogate(self) -> bool {
|
||||
matches!(self, 0xD800..=0xDFFF)
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "u32"]
|
||||
|
|
|
@ -29,7 +29,6 @@ fn aarch64_linux() {
|
|||
println!("neon: {}", is_aarch64_feature_detected!("neon"));
|
||||
println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
|
||||
println!("pmull: {}", is_aarch64_feature_detected!("pmull"));
|
||||
println!("fp: {}", is_aarch64_feature_detected!("fp"));
|
||||
println!("fp16: {}", is_aarch64_feature_detected!("fp16"));
|
||||
println!("sve: {}", is_aarch64_feature_detected!("sve"));
|
||||
println!("crc: {}", is_aarch64_feature_detected!("crc"));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-include ../tools.mk
|
||||
|
||||
all:
|
||||
$(RUSTC) --edition=2018 --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg feature=\"external_crate\" --cfg no_global_oom_handling
|
||||
$(RUSTC) --edition=2021 --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg no_global_oom_handling
|
||||
|
|
|
@ -41,7 +41,7 @@ define MK_TARGETS
|
|||
# now.
|
||||
$(1): simd.rs
|
||||
$$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs \
|
||||
-C target-feature='+fp,+neon,+sse2' -C extra-filename=-$(1)
|
||||
-C target-feature='+neon,+sse2' -C extra-filename=-$(1)
|
||||
endef
|
||||
|
||||
$(foreach targetxxx,$(TARGETS),$(eval $(call MK_TARGETS,$(targetxxx))))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// only-aarch64
|
||||
// compile-flags: -C target-feature=+fp
|
||||
// compile-flags: -C target-feature=+neon
|
||||
|
||||
#![feature(asm_const, asm_sym)]
|
||||
|
||||
|
|
23
src/test/ui/target-feature/aarch64-neon-works.rs
Normal file
23
src/test/ui/target-feature/aarch64-neon-works.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// only-aarch64
|
||||
// run-pass
|
||||
#![allow(dead_code)]
|
||||
use std::arch::*;
|
||||
use std::arch::aarch64::*;
|
||||
|
||||
// Smoke test to verify aarch64 code that enables NEON compiles.
|
||||
fn main() {
|
||||
let _zero = if is_aarch64_feature_detected!("neon") {
|
||||
unsafe {
|
||||
let zeros = zero_vector();
|
||||
vgetq_lane_u8::<1>(zeros)
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[target_feature(enable = "neon")]
|
||||
unsafe fn zero_vector() -> uint8x16_t {
|
||||
vmovq_n_u8(0)
|
||||
}
|
58
src/test/ui/target-feature/feature-hierarchy.rs
Normal file
58
src/test/ui/target-feature/feature-hierarchy.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
// revisions: aarch64-neon aarch64-sve2
|
||||
// [aarch64-neon] compile-flags: -Ctarget-feature=+neon --target=aarch64-unknown-linux-gnu
|
||||
// [aarch64-neon] needs-llvm-components: aarch64
|
||||
// [aarch64-sve2] compile-flags: -Ctarget-feature=-neon,+sve2 --target=aarch64-unknown-linux-gnu
|
||||
// [aarch64-sve2] needs-llvm-components: aarch64
|
||||
// build-pass
|
||||
#![no_core]
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(intrinsics, rustc_attrs, no_core, lang_items, staged_api)]
|
||||
#![stable(feature = "test", since = "1.0.0")]
|
||||
|
||||
// Tests vetting "feature hierarchies" in the cases where we impose them.
|
||||
|
||||
// Supporting minimal rust core code
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
impl Copy for bool {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
#[rustc_const_stable(feature = "test", since = "1.0.0")]
|
||||
fn unreachable() -> !;
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! cfg {
|
||||
($($cfg:tt)*) => {};
|
||||
}
|
||||
|
||||
// Test code
|
||||
const fn do_or_die(cond: bool) {
|
||||
if cond {
|
||||
} else {
|
||||
unsafe { unreachable() }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert {
|
||||
($x:expr $(,)?) => {
|
||||
const _: () = do_or_die($x);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[cfg(aarch64_neon)]
|
||||
fn check_neon_not_sve2() {
|
||||
// This checks that a normal aarch64 target doesn't suddenly jump up the feature hierarchy.
|
||||
assert!(cfg!(target_feature = "neon"));
|
||||
assert!(cfg!(not(target_feature = "sve2")));
|
||||
}
|
||||
|
||||
#[cfg(aarch64_sve2)]
|
||||
fn check_sve2_includes_neon() {
|
||||
// This checks that aarch64's sve2 includes neon
|
||||
assert!(cfg!(target_feature = "neon"));
|
||||
assert!(cfg!(target_feature = "sve2"));
|
||||
}
|
64
src/test/ui/target-feature/no-llvm-leaks.rs
Normal file
64
src/test/ui/target-feature/no-llvm-leaks.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
// revisions: aarch64 x86-64
|
||||
// [aarch64] compile-flags: -Ctarget-feature=+neon,+fp16,+fhm --target=aarch64-unknown-linux-gnu
|
||||
// [aarch64] needs-llvm-components: aarch64
|
||||
// [x86-64] compile-flags: -Ctarget-feature=+sse4.2,+rdrand --target=x86_64-unknown-linux-gnu
|
||||
// [x86-64] needs-llvm-components: x86
|
||||
// build-pass
|
||||
#![no_core]
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(intrinsics, rustc_attrs, no_core, lang_items, staged_api)]
|
||||
#![stable(feature = "test", since = "1.0.0")]
|
||||
|
||||
// Supporting minimal rust core code
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
impl Copy for bool {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
#[rustc_const_stable(feature = "test", since = "1.0.0")]
|
||||
fn unreachable() -> !;
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! cfg {
|
||||
($($cfg:tt)*) => {};
|
||||
}
|
||||
|
||||
// Test code
|
||||
const fn do_or_die(cond: bool) {
|
||||
if cond {
|
||||
} else {
|
||||
unsafe { unreachable() }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert {
|
||||
($x:expr $(,)?) => {
|
||||
const _: () = do_or_die($x);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn check_aarch64() {
|
||||
// This checks that the rustc feature name is used, not the LLVM feature.
|
||||
assert!(cfg!(target_feature = "neon"));
|
||||
assert!(cfg!(not(target_feature = "fp-armv8")));
|
||||
assert!(cfg!(target_feature = "fhm"));
|
||||
assert!(cfg!(not(target_feature = "fp16fml")));
|
||||
assert!(cfg!(target_feature = "fp16"));
|
||||
assert!(cfg!(not(target_feature = "fullfp16")));
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn check_x86_64() {
|
||||
// This checks that the rustc feature name is used, not the LLVM feature.
|
||||
assert!(cfg!(target_feature = "rdrand"));
|
||||
assert!(cfg!(not(target_feature = "rdrnd")));
|
||||
|
||||
// Likewise: We enable LLVM's crc32 feature with SSE4.2, but Rust says it's just SSE4.2
|
||||
assert!(cfg!(target_feature = "sse4.2"));
|
||||
assert!(cfg!(not(target_feature = "crc32")));
|
||||
}
|
Loading…
Add table
Reference in a new issue