diff options
| author | Ralf Jung <post@ralfj.de> | 2025-08-21 14:48:22 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-21 14:48:22 +0000 |
| commit | 802de3ded1682319ba125fb8d58cd4bebdb8a5ba (patch) | |
| tree | dd1093afbfb803515cab44d11749a61a05af5475 /library | |
| parent | 6370c8ed1c1e846003d6ab435a9673615b67ada3 (diff) | |
| parent | f702219ba61d94a50ecb581a4e0ab51dc459e99e (diff) | |
Merge pull request #4534 from rust-lang/rustup-2025-08-21
Automatic Rustup
Diffstat (limited to 'library')
| -rw-r--r-- | library/Cargo.lock | 4 | ||||
| -rw-r--r-- | library/Cargo.toml | 1 | ||||
| -rw-r--r-- | library/alloc/src/alloc.rs | 1 | ||||
| -rw-r--r-- | library/core/src/cmp.rs | 15 | ||||
| -rw-r--r-- | library/core/src/intrinsics/mod.rs | 51 | ||||
| -rw-r--r-- | library/core/src/num/int_macros.rs | 42 | ||||
| -rw-r--r-- | library/core/src/num/nonzero.rs | 48 | ||||
| -rw-r--r-- | library/core/src/num/uint_macros.rs | 48 | ||||
| -rw-r--r-- | library/coretests/tests/lib.rs | 1 | ||||
| -rw-r--r-- | library/coretests/tests/nonzero.rs | 108 | ||||
| -rw-r--r-- | library/coretests/tests/num/int_macros.rs | 40 | ||||
| -rw-r--r-- | library/coretests/tests/num/uint_macros.rs | 34 | ||||
| -rw-r--r-- | library/std/src/io/mod.rs | 9 | ||||
| -rw-r--r-- | library/std_detect/Cargo.toml | 4 | ||||
| -rw-r--r-- | library/std_detect/src/detect/arch/riscv.rs | 197 | ||||
| -rw-r--r-- | library/std_detect/src/detect/arch/x86.rs | 6 | ||||
| -rw-r--r-- | library/std_detect/src/detect/os/x86.rs | 66 |
17 files changed, 541 insertions, 134 deletions
diff --git a/library/Cargo.lock b/library/Cargo.lock index 656576d2d8e..418a5f78397 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -336,9 +336,9 @@ dependencies = [ name = "std_detect" version = "0.1.5" dependencies = [ - "alloc", - "core", "libc", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", ] [[package]] diff --git a/library/Cargo.toml b/library/Cargo.toml index a79c17fc4f7..e30e6240942 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -59,4 +59,3 @@ rustflags = ["-Cpanic=abort"] rustc-std-workspace-core = { path = 'rustc-std-workspace-core' } rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' } rustc-std-workspace-std = { path = 'rustc-std-workspace-std' } -compiler_builtins = { path = "compiler-builtins/compiler-builtins" } diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index c9b98fa4e5a..76630a746dd 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -17,6 +17,7 @@ unsafe extern "Rust" { #[rustc_allocator] #[rustc_nounwind] #[rustc_std_internal_symbol] + #[rustc_allocator_zeroed_variant = "__rust_alloc_zeroed"] fn __rust_alloc(size: usize, align: usize) -> *mut u8; #[rustc_deallocator] #[rustc_nounwind] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index a64fade285b..ab018fa2675 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1554,6 +1554,9 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T { /// /// Returns the first argument if the comparison determines them to be equal. /// +/// The parameter order is preserved when calling the `compare` function, i.e. `v1` is +/// always passed as the first argument and `v2` as the second. +/// /// # Examples /// /// ``` @@ -1574,7 +1577,7 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T { #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { - if compare(&v2, &v1).is_lt() { v2 } else { v1 } + if compare(&v1, &v2).is_le() { v1 } else { v2 } } /// Returns the element that gives the minimum value from the specified function. @@ -1646,6 +1649,9 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T { /// /// Returns the second argument if the comparison determines them to be equal. /// +/// The parameter order is preserved when calling the `compare` function, i.e. `v1` is +/// always passed as the first argument and `v2` as the second. +/// /// # Examples /// /// ``` @@ -1666,7 +1672,7 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T { #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { - if compare(&v2, &v1).is_lt() { v1 } else { v2 } + if compare(&v1, &v2).is_gt() { v1 } else { v2 } } /// Returns the element that gives the maximum value from the specified function. @@ -1745,6 +1751,9 @@ where /// /// Returns `[v1, v2]` if the comparison determines them to be equal. /// +/// The parameter order is preserved when calling the `compare` function, i.e. `v1` is +/// always passed as the first argument and `v2` as the second. +/// /// # Examples /// /// ``` @@ -1769,7 +1778,7 @@ pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2] where F: FnOnce(&T, &T) -> Ordering, { - if compare(&v2, &v1).is_lt() { [v2, v1] } else { [v1, v2] } + if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] } } /// Returns minimum and maximum values with respect to the specified key function. diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index dd838d494bc..904aa52c784 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -261,53 +261,72 @@ pub unsafe fn atomic_fence<const ORD: AtomicOrdering>(); pub unsafe fn atomic_singlethreadfence<const ORD: AtomicOrdering>(); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction -/// if supported; otherwise, it is a no-op. +/// for the given address if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// -/// The `locality` argument must be a constant integer and is a temporal locality specifier -/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality, +/// to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn prefetch_read_data<T>(data: *const T, locality: i32); +#[miri::intrinsic_fallback_is_spec] +pub const fn prefetch_read_data<T, const LOCALITY: i32>(data: *const T) { + // This operation is a no-op, unless it is overridden by the backend. + let _ = data; +} + /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction -/// if supported; otherwise, it is a no-op. +/// for the given address if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// -/// The `locality` argument must be a constant integer and is a temporal locality specifier -/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality, +/// to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn prefetch_write_data<T>(data: *const T, locality: i32); +#[miri::intrinsic_fallback_is_spec] +pub const fn prefetch_write_data<T, const LOCALITY: i32>(data: *const T) { + // This operation is a no-op, unless it is overridden by the backend. + let _ = data; +} + /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction -/// if supported; otherwise, it is a no-op. +/// for the given address if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// -/// The `locality` argument must be a constant integer and is a temporal locality specifier -/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality, +/// to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn prefetch_read_instruction<T>(data: *const T, locality: i32); +#[miri::intrinsic_fallback_is_spec] +pub const fn prefetch_read_instruction<T, const LOCALITY: i32>(data: *const T) { + // This operation is a no-op, unless it is overridden by the backend. + let _ = data; +} + /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction -/// if supported; otherwise, it is a no-op. +/// for the given address if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// -/// The `locality` argument must be a constant integer and is a temporal locality specifier -/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality, +/// to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn prefetch_write_instruction<T>(data: *const T, locality: i32); +#[miri::intrinsic_fallback_is_spec] +pub const fn prefetch_write_instruction<T, const LOCALITY: i32>(data: *const T) { + // This operation is a no-op, unless it is overridden by the backend. + let _ = data; +} /// Executes a breakpoint trap, for inspection by a debugger. /// diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index dbcccdf497c..25864db5fea 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -209,6 +209,48 @@ macro_rules! int_impl { self & self.wrapping_neg() } + /// Returns the index of the highest bit set to one in `self`, or `None` + /// if `self` is `0`. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_lowest_highest_one)] + /// + #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".highest_one(), None);")] + #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".highest_one(), Some(0));")] + #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".highest_one(), Some(4));")] + #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".highest_one(), Some(4));")] + /// ``` + #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn highest_one(self) -> Option<u32> { + (self as $UnsignedT).highest_one() + } + + /// Returns the index of the lowest bit set to one in `self`, or `None` + /// if `self` is `0`. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_lowest_highest_one)] + /// + #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".lowest_one(), None);")] + #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".lowest_one(), Some(0));")] + #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".lowest_one(), Some(4));")] + #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".lowest_one(), Some(0));")] + /// ``` + #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn lowest_one(self) -> Option<u32> { + (self as $UnsignedT).lowest_one() + } + /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size. /// /// This produces the same result as an `as` cast, but ensures that the bit-width remains diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 308d722f5d5..e02d9260a16 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -681,6 +681,54 @@ macro_rules! nonzero_integer { unsafe { NonZero::new_unchecked(n) } } + /// Returns the index of the highest bit set to one in `self`. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_lowest_highest_one)] + /// + /// # use core::num::NonZero; + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1)?.highest_one(), 0);")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x10)?.highest_one(), 4);")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1f)?.highest_one(), 4);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn highest_one(self) -> u32 { + Self::BITS - 1 - self.leading_zeros() + } + + /// Returns the index of the lowest bit set to one in `self`. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_lowest_highest_one)] + /// + /// # use core::num::NonZero; + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1)?.lowest_one(), 0);")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x10)?.lowest_one(), 4);")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1f)?.lowest_one(), 0);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn lowest_one(self) -> u32 { + self.trailing_zeros() + } + /// Returns the number of ones in the binary representation of `self`. /// /// # Examples diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 186c6f32cff..10d9498d15e 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -261,6 +261,54 @@ macro_rules! uint_impl { self & self.wrapping_neg() } + /// Returns the index of the highest bit set to one in `self`, or `None` + /// if `self` is `0`. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_lowest_highest_one)] + /// + #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".highest_one(), None);")] + #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".highest_one(), Some(0));")] + #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".highest_one(), Some(4));")] + #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".highest_one(), Some(4));")] + /// ``` + #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn highest_one(self) -> Option<u32> { + match NonZero::new(self) { + Some(v) => Some(v.highest_one()), + None => None, + } + } + + /// Returns the index of the lowest bit set to one in `self`, or `None` + /// if `self` is `0`. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_lowest_highest_one)] + /// + #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".lowest_one(), None);")] + #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".lowest_one(), Some(0));")] + #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".lowest_one(), Some(4));")] + #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".lowest_one(), Some(0));")] + /// ``` + #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn lowest_one(self) -> Option<u32> { + match NonZero::new(self) { + Some(v) => Some(v.lowest_one()), + None => None, + } + } + /// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size. /// /// This produces the same result as an `as` cast, but ensures that the bit-width remains diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b128acfc000..d2281b1df2f 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -54,6 +54,7 @@ #![feature(generic_assert_internals)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] +#![feature(int_lowest_highest_one)] #![feature(int_roundings)] #![feature(ip)] #![feature(is_ascii_octdigit)] diff --git a/library/coretests/tests/nonzero.rs b/library/coretests/tests/nonzero.rs index eb06c34fd02..69e4ed9c36b 100644 --- a/library/coretests/tests/nonzero.rs +++ b/library/coretests/tests/nonzero.rs @@ -462,3 +462,111 @@ fn test_nonzero_fmt() { assert_eq!(i, nz); } + +#[test] +fn test_nonzero_highest_one() { + macro_rules! nonzero_int_impl { + ($($T:ty),+) => { + $( + { + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!(NonZero::<$T>::new(1 << i).unwrap().highest_one(), i); + if i > <$T>::BITS { + // Set lowest bits. + assert_eq!( + NonZero::<$T>::new(<$T>::MAX >> i).unwrap().highest_one(), + <$T>::BITS - i - 2, + ); + } + // Set highest bits. + assert_eq!( + NonZero::<$T>::new(-1 << i).unwrap().highest_one(), + <$T>::BITS - 1, + ); + } + } + )+ + }; + } + + macro_rules! nonzero_uint_impl { + ($($T:ty),+) => { + $( + { + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!(NonZero::<$T>::new(1 << i).unwrap().highest_one(), i); + // Set lowest bits. + assert_eq!( + NonZero::<$T>::new(<$T>::MAX >> i).unwrap().highest_one(), + <$T>::BITS - i - 1, + ); + // Set highest bits. + assert_eq!( + NonZero::<$T>::new(<$T>::MAX << i).unwrap().highest_one(), + <$T>::BITS - 1, + ); + } + } + )+ + }; + } + + nonzero_int_impl!(i8, i16, i32, i64, i128, isize); + nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); +} + +#[test] +fn test_nonzero_lowest_one() { + macro_rules! nonzero_int_impl { + ($($T:ty),+) => { + $( + { + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!(NonZero::<$T>::new(1 << i).unwrap().lowest_one(), i); + if i > <$T>::BITS { + // Set lowest bits. + assert_eq!( + NonZero::<$T>::new(<$T>::MAX >> i).unwrap().lowest_one(), + 0, + ); + } + // Set highest bits. + assert_eq!( + NonZero::<$T>::new(-1 << i).unwrap().lowest_one(), + i, + ); + } + } + )+ + }; + } + + macro_rules! nonzero_uint_impl { + ($($T:ty),+) => { + $( + { + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!(NonZero::<$T>::new(1 << i).unwrap().lowest_one(), i); + // Set lowest bits. + assert_eq!( + NonZero::<$T>::new(<$T>::MAX >> i).unwrap().lowest_one(), + 0, + ); + // Set highest bits. + assert_eq!( + NonZero::<$T>::new(<$T>::MAX << i).unwrap().lowest_one(), + i, + ); + } + } + )+ + }; + } + + nonzero_int_impl!(i8, i16, i32, i64, i128, isize); + nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); +} diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index ca32fce861f..1611a6466f5 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -228,6 +228,46 @@ macro_rules! int_module { } #[test] + fn test_highest_one() { + const ZERO: $T = 0; + const ONE: $T = 1; + const MINUS_ONE: $T = -1; + + assert_eq!(ZERO.highest_one(), None); + + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!((ONE << i).highest_one(), Some(i)); + if i != <$T>::BITS - 1 { + // Set lowest bits. + assert_eq!((<$T>::MAX >> i).highest_one(), Some(<$T>::BITS - i - 2)); + } + // Set highest bits. + assert_eq!((MINUS_ONE << i).highest_one(), Some(<$T>::BITS - 1)); + } + } + + #[test] + fn test_lowest_one() { + const ZERO: $T = 0; + const ONE: $T = 1; + const MINUS_ONE: $T = -1; + + assert_eq!(ZERO.lowest_one(), None); + + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!((ONE << i).lowest_one(), Some(i)); + if i != <$T>::BITS - 1 { + // Set lowest bits. + assert_eq!((<$T>::MAX >> i).lowest_one(), Some(0)); + } + // Set highest bits. + assert_eq!((MINUS_ONE << i).lowest_one(), Some(i)); + } + } + + #[test] fn test_from_str() { fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> { std::str::FromStr::from_str(t).ok() diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 8f389de70aa..c7d10ea4d88 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -184,6 +184,40 @@ macro_rules! uint_module { } } + #[test] + fn test_highest_one() { + const ZERO: $T = 0; + const ONE: $T = 1; + + assert_eq!(ZERO.highest_one(), None); + + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!((ONE << i).highest_one(), Some(i)); + // Set lowest bits. + assert_eq!((<$T>::MAX >> i).highest_one(), Some(<$T>::BITS - i - 1)); + // Set highest bits. + assert_eq!((<$T>::MAX << i).highest_one(), Some(<$T>::BITS - 1)); + } + } + + #[test] + fn test_lowest_one() { + const ZERO: $T = 0; + const ONE: $T = 1; + + assert_eq!(ZERO.lowest_one(), None); + + for i in 0..<$T>::BITS { + // Set single bit. + assert_eq!((ONE << i).lowest_one(), Some(i)); + // Set lowest bits. + assert_eq!((<$T>::MAX >> i).lowest_one(), Some(0)); + // Set highest bits. + assert_eq!((<$T>::MAX << i).lowest_one(), Some(i)); + } + } + fn from_str<T: core::str::FromStr>(t: &str) -> Option<T> { core::str::FromStr::from_str(t).ok() } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index d351ee5e739..ff0e29e04c2 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2461,7 +2461,7 @@ pub trait BufRead: Read { /// delimiter or EOF is found. /// /// If successful, this function will return the total number of bytes read, - /// including the delimiter byte. + /// including the delimiter byte if found. /// /// This is useful for efficiently skipping data such as NUL-terminated strings /// in binary file formats without buffering. @@ -2489,7 +2489,7 @@ pub trait BufRead: Read { /// ``` /// use std::io::{self, BufRead}; /// - /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0"); + /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0!"); /// /// // read name /// let mut name = Vec::new(); @@ -2509,6 +2509,11 @@ pub trait BufRead: Read { /// .expect("reading from cursor won't fail"); /// assert_eq!(num_bytes, 11); /// assert_eq!(animal, b"Crustacean\0"); + /// + /// // reach EOF + /// let num_bytes = cursor.skip_until(b'\0') + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 1); /// ``` #[stable(feature = "bufread_skip_until", since = "1.83.0")] fn skip_until(&mut self, byte: u8) -> Result<usize> { diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml index 33e6617c381..2739bb59230 100644 --- a/library/std_detect/Cargo.toml +++ b/library/std_detect/Cargo.toml @@ -21,8 +21,8 @@ is-it-maintained-open-issues = { repository = "rust-lang/stdarch" } maintenance = { status = "experimental" } [dependencies] -core = { path = "../core" } -alloc = { path = "../alloc" } +core = { version = "1.0.0", package = 'rustc-std-workspace-core' } +alloc = { version = "1.0.0", package = 'rustc-std-workspace-alloc' } [target.'cfg(not(windows))'.dependencies] libc = { version = "0.2.0", optional = true, default-features = false } diff --git a/library/std_detect/src/detect/arch/riscv.rs b/library/std_detect/src/detect/arch/riscv.rs index 1d21b1d4855..1e57d09edb1 100644 --- a/library/std_detect/src/detect/arch/riscv.rs +++ b/library/std_detect/src/detect/arch/riscv.rs @@ -37,90 +37,121 @@ features! { /// /// # Unprivileged Specification /// - /// The supported ratified RISC-V instruction sets are as follows: + /// The supported ratified RISC-V instruction sets are as follows (OS + /// columns denote runtime feature detection support with or without the + /// minimum supported version): /// - /// * RV32E: `"rv32e"` - /// * RV32I: `"rv32i"` - /// * RV64I: `"rv64i"` - /// * A: `"a"` - /// * Zaamo: `"zaamo"` - /// * Zalrsc: `"zalrsc"` - /// * B: `"b"` - /// * Zba: `"zba"` - /// * Zbb: `"zbb"` - /// * Zbs: `"zbs"` - /// * C: `"c"` - /// * Zca: `"zca"` - /// * Zcd: `"zcd"` (if D is enabled) - /// * Zcf: `"zcf"` (if F is enabled on RV32) - /// * D: `"d"` - /// * F: `"f"` - /// * M: `"m"` - /// * Q: `"q"` - /// * V: `"v"` - /// * Zve32x: `"zve32x"` - /// * Zve32f: `"zve32f"` - /// * Zve64x: `"zve64x"` - /// * Zve64f: `"zve64f"` - /// * Zve64d: `"zve64d"` - /// * Zicbom: `"zicbom"` - /// * Zicboz: `"zicboz"` - /// * Zicntr: `"zicntr"` - /// * Zicond: `"zicond"` - /// * Zicsr: `"zicsr"` - /// * Zifencei: `"zifencei"` - /// * Zihintntl: `"zihintntl"` - /// * Zihintpause: `"zihintpause"` - /// * Zihpm: `"zihpm"` - /// * Zimop: `"zimop"` - /// * Zabha: `"zabha"` - /// * Zacas: `"zacas"` - /// * Zawrs: `"zawrs"` - /// * Zfa: `"zfa"` - /// * Zfbfmin: `"zfbfmin"` - /// * Zfh: `"zfh"` - /// * Zfhmin: `"zfhmin"` - /// * Zfinx: `"zfinx"` - /// * Zdinx: `"zdinx"` - /// * Zhinx: `"zhinx"` - /// * Zhinxmin: `"zhinxmin"` - /// * Zcb: `"zcb"` - /// * Zcmop: `"zcmop"` - /// * Zbc: `"zbc"` - /// * Zbkb: `"zbkb"` - /// * Zbkc: `"zbkc"` - /// * Zbkx: `"zbkx"` - /// * Zk: `"zk"` - /// * Zkn: `"zkn"` - /// * Zknd: `"zknd"` - /// * Zkne: `"zkne"` - /// * Zknh: `"zknh"` - /// * Zkr: `"zkr"` - /// * Zks: `"zks"` - /// * Zksed: `"zksed"` - /// * Zksh: `"zksh"` - /// * Zkt: `"zkt"` - /// * Zvbb: `"zvbb"` - /// * Zvbc: `"zvbc"` - /// * Zvfbfmin: `"zvfbfmin"` - /// * Zvfbfwma: `"zvfbfwma"` - /// * Zvfh: `"zvfh"` - /// * Zvfhmin: `"zvfhmin"` - /// * Zvkb: `"zvkb"` - /// * Zvkg: `"zvkg"` - /// * Zvkn: `"zvkn"` - /// * Zvkned: `"zvkned"` - /// * Zvknha: `"zvknha"` - /// * Zvknhb: `"zvknhb"` - /// * Zvknc: `"zvknc"` - /// * Zvkng: `"zvkng"` - /// * Zvks: `"zvks"` - /// * Zvksed: `"zvksed"` - /// * Zvksh: `"zvksh"` - /// * Zvksc: `"zvksc"` - /// * Zvksg: `"zvksg"` - /// * Zvkt: `"zvkt"` - /// * Ztso: `"ztso"` + /// | Literal | Base | Linux | + /// |:---------- |:------- |:---------- | + /// | `"rv32e"` | RV32E | No | + /// | `"rv32i"` | RV32I | Yes [^ima] | + /// | `"rv64i"` | RV64I | Yes [^ima] | + /// + /// | Literal | Extension | Linux | + /// |:--------------- |:----------- |:------------------- | + /// | `"a"` | A | Yes [^ima] | + /// | `"b"` | B | 6.5 | + /// | `"c"` | C | Yes | + /// | `"d"` | D | Yes | + /// | `"f"` | F | Yes | + /// | `"m"` | M | Yes [^ima] | + /// | `"q"` | Q | No | + /// | `"v"` | V | 6.5 | + /// | `"zaamo"` | Zaamo | 6.15 [^ima] [^dep] | + /// | `"zabha"` | Zabha | 6.16 | + /// | `"zacas"` | Zacas | 6.8 | + /// | `"zalrsc"` | Zalrsc | 6.15 [^ima] [^dep] | + /// | `"zawrs"` | Zawrs | 6.11 | + /// | `"zba"` | Zba | 6.5 | + /// | `"zbb"` | Zbb | 6.5 | + /// | `"zbc"` | Zbc | 6.8 | + /// | `"zbkb"` | Zbkb | 6.8 | + /// | `"zbkc"` | Zbkc | 6.8 | + /// | `"zbkx"` | Zbkx | 6.8 | + /// | `"zbs"` | Zbs | 6.5 | + /// | `"zca"` | Zca | 6.11 [^dep] | + /// | `"zcb"` | Zcb | 6.11 | + /// | `"zcd"` | Zcd | 6.11 [^dep] | + /// | `"zcf"` | Zcf | 6.11 [^dep] | + /// | `"zcmop"` | Zcmop | 6.11 | + /// | `"zdinx"` | Zdinx | No | + /// | `"zfa"` | Zfa | 6.8 | + /// | `"zfbfmin"` | Zfbfmin | 6.15 | + /// | `"zfh"` | Zfh | 6.8 | + /// | `"zfhmin"` | Zfhmin | 6.8 | + /// | `"zfinx"` | Zfinx | No | + /// | `"zhinx"` | Zhinx | No | + /// | `"zhinxmin"` | Zhinxmin | No | + /// | `"zicbom"` | Zicbom | 6.15 | + /// | `"zicboz"` | Zicboz | 6.7 | + /// | `"zicntr"` | Zicntr | 6.15 [^ima] [^cntr] | + /// | `"zicond"` | Zicond | 6.8 | + /// | `"zicsr"` | Zicsr | No [^ima] [^dep] | + /// | `"zifencei"` | Zifencei | No [^ima] | + /// | `"zihintntl"` | Zihintntl | 6.8 | + /// | `"zihintpause"` | Zihintpause | 6.10 | + /// | `"zihpm"` | Zihpm | 6.15 [^cntr] | + /// | `"zimop"` | Zimop | 6.11 | + /// | `"zk"` | Zk | No [^zkr] | + /// | `"zkn"` | Zkn | 6.8 | + /// | `"zknd"` | Zknd | 6.8 | + /// | `"zkne"` | Zkne | 6.8 | + /// | `"zknh"` | Zknh | 6.8 | + /// | `"zkr"` | Zkr | No [^zkr] | + /// | `"zks"` | Zks | 6.8 | + /// | `"zksed"` | Zksed | 6.8 | + /// | `"zksh"` | Zksh | 6.8 | + /// | `"zkt"` | Zkt | 6.8 | + /// | `"ztso"` | Ztso | 6.8 | + /// | `"zvbb"` | Zvbb | 6.8 | + /// | `"zvbc"` | Zvbc | 6.8 | + /// | `"zve32f"` | Zve32f | 6.11 [^dep] | + /// | `"zve32x"` | Zve32x | 6.11 [^dep] | + /// | `"zve64d"` | Zve64d | 6.11 [^dep] | + /// | `"zve64f"` | Zve64f | 6.11 [^dep] | + /// | `"zve64x"` | Zve64x | 6.11 [^dep] | + /// | `"zvfbfmin"` | Zvfbfmin | 6.15 | + /// | `"zvfbfwma"` | Zvfbfwma | 6.15 | + /// | `"zvfh"` | Zvfh | 6.8 | + /// | `"zvfhmin"` | Zvfhmin | 6.8 | + /// | `"zvkb"` | Zvkb | 6.8 | + /// | `"zvkg"` | Zvkg | 6.8 | + /// | `"zvkn"` | Zvkn | 6.8 | + /// | `"zvknc"` | Zvknc | 6.8 | + /// | `"zvkned"` | Zvkned | 6.8 | + /// | `"zvkng"` | Zvkng | 6.8 | + /// | `"zvknha"` | Zvknha | 6.8 | + /// | `"zvknhb"` | Zvknhb | 6.8 | + /// | `"zvks"` | Zvks | 6.8 | + /// | `"zvksc"` | Zvksc | 6.8 | + /// | `"zvksed"` | Zvksed | 6.8 | + /// | `"zvksg"` | Zvksg | 6.8 | + /// | `"zvksh"` | Zvksh | 6.8 | + /// | `"zvkt"` | Zvkt | 6.8 | + /// + /// [^ima]: Or enabled when the IMA base behavior is detected on the Linux + /// kernel version 6.4 or later (for bases, the only matching one -- either + /// `"rv32i"` or `"rv64i"` -- is enabled). + /// + /// [^cntr]: Even if this extension is available, it does not necessarily + /// mean all performance counters are accessible. + /// For example, accesses to all performance counters except `time` + /// (wall-clock) are blocked by default on the Linux kernel + /// version 6.6 or later. + /// Also beware that, even if performance counters like `cycle` and + /// `instret` are accessible, their value can be unreliable (e.g. returning + /// the constant value) under certain circumstances. + /// + /// [^dep]: Or enabled as a dependency of another extension (a superset) + /// even if runtime detection of this feature itself is not supported (as + /// long as the runtime detection of the superset is supported). + /// + /// [^zkr]: Linux does not report existence of this extension even if + /// supported by the hardware mainly because the `seed` CSR on the Zkr + /// extension (which provides hardware-based randomness) is normally + /// inaccessible from the user mode. + /// For the Zk extension features except this CSR, check existence of both + /// `"zkn"` and `"zkt"` features instead. /// /// There's also bases and extensions marked as standard instruction set, /// but they are in frozen or draft state. These instruction sets are also diff --git a/library/std_detect/src/detect/arch/x86.rs b/library/std_detect/src/detect/arch/x86.rs index 28b3e3cfb35..bd749b88f56 100644 --- a/library/std_detect/src/detect/arch/x86.rs +++ b/library/std_detect/src/detect/arch/x86.rs @@ -233,6 +233,12 @@ features! { /// AMX-TF32 (TensorFloat32 Operations) @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_transpose: "amx-transpose"; /// AMX-TRANSPOSE (Matrix Transpose Operations) + @FEATURE: #[unstable(feature = "apx_target_feature", issue = "139284")] apxf: "apxf"; + /// APX-F (Advanced Performance Extensions - Foundation) + @FEATURE: #[unstable(feature = "avx10_target_feature", issue = "138843")] avx10_1: "avx10.1"; + /// AVX10.1 + @FEATURE: #[unstable(feature = "avx10_target_feature", issue = "138843")] avx10_2: "avx10.2"; + /// AVX10.2 @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] f16c: "f16c"; /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats) @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fma: "fma"; diff --git a/library/std_detect/src/detect/os/x86.rs b/library/std_detect/src/detect/os/x86.rs index 20f848ab05c..cf11d833312 100644 --- a/library/std_detect/src/detect/os/x86.rs +++ b/library/std_detect/src/detect/os/x86.rs @@ -137,6 +137,32 @@ pub(crate) fn detect_features() -> cache::Initializer { enable(ebx, 2, Feature::widekl); } + // This detects ABM on AMD CPUs and LZCNT on Intel CPUs. + // On intel CPUs with popcnt, lzcnt implements the + // "missing part" of ABM, so we map both to the same + // internal feature. + // + // The `is_x86_feature_detected!("lzcnt")` macro then + // internally maps to Feature::abm. + enable(extended_proc_info_ecx, 5, Feature::lzcnt); + + // As Hygon Dhyana originates from AMD technology and shares most of the architecture with + // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series + // number(Family 18h). + // + // For CPUID feature bits, Hygon Dhyana(family 18h) share the same definition with AMD + // family 17h. + // + // Related AMD CPUID specification is https://www.amd.com/system/files/TechDocs/25481.pdf. + // Related Hygon kernel patch can be found on + // http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn + if vendor_id == *b"AuthenticAMD" || vendor_id == *b"HygonGenuine" { + // These features are available on AMD arch CPUs: + enable(extended_proc_info_ecx, 6, Feature::sse4a); + enable(extended_proc_info_ecx, 21, Feature::tbm); + enable(extended_proc_info_ecx, 11, Feature::xop); + } + // `XSAVE` and `AVX` support: let cpu_xsave = bit::test(proc_info_ecx as usize, 26); if cpu_xsave { @@ -161,6 +187,7 @@ pub(crate) fn detect_features() -> cache::Initializer { // * AVX -> `XCR0.AVX[2]` // * AVX-512 -> `XCR0.AVX-512[7:5]`. // * AMX -> `XCR0.AMX[18:17]` + // * APX -> `XCR0.APX[19]` // // by setting the corresponding bits of `XCR0` to `1`. // @@ -173,6 +200,8 @@ pub(crate) fn detect_features() -> cache::Initializer { let os_avx512_support = xcr0 & 0xe0 == 0xe0; // Test `XCR0.AMX[18:17]` with the mask `0b110_0000_0000_0000_0000 == 0x60000` let os_amx_support = xcr0 & 0x60000 == 0x60000; + // Test `XCR0.APX[19]` with the mask `0b1000_0000_0000_0000_0000 == 0x80000` + let os_apx_support = xcr0 & 0x80000 == 0x80000; // Only if the OS and the CPU support saving/restoring the AVX // registers we enable `xsave` support: @@ -262,33 +291,20 @@ pub(crate) fn detect_features() -> cache::Initializer { enable(amx_feature_flags_eax, 8, Feature::amx_movrs); } } - } - } - // This detects ABM on AMD CPUs and LZCNT on Intel CPUs. - // On intel CPUs with popcnt, lzcnt implements the - // "missing part" of ABM, so we map both to the same - // internal feature. - // - // The `is_x86_feature_detected!("lzcnt")` macro then - // internally maps to Feature::abm. - enable(extended_proc_info_ecx, 5, Feature::lzcnt); + if os_apx_support { + enable(extended_features_edx_leaf_1, 21, Feature::apxf); + } - // As Hygon Dhyana originates from AMD technology and shares most of the architecture with - // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series - // number(Family 18h). - // - // For CPUID feature bits, Hygon Dhyana(family 18h) share the same definition with AMD - // family 17h. - // - // Related AMD CPUID specification is https://www.amd.com/system/files/TechDocs/25481.pdf. - // Related Hygon kernel patch can be found on - // http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn - if vendor_id == *b"AuthenticAMD" || vendor_id == *b"HygonGenuine" { - // These features are available on AMD arch CPUs: - enable(extended_proc_info_ecx, 6, Feature::sse4a); - enable(extended_proc_info_ecx, 21, Feature::tbm); - enable(extended_proc_info_ecx, 11, Feature::xop); + let avx10_1 = enable(extended_features_edx_leaf_1, 19, Feature::avx10_1); + if avx10_1 { + let CpuidResult { ebx, .. } = unsafe { __cpuid(0x24) }; + let avx10_version = ebx & 0xff; + if avx10_version >= 2 { + value.set(Feature::avx10_2 as u32); + } + } + } } } |
