diff options
| author | bors <bors@rust-lang.org> | 2021-07-09 09:16:27 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-07-09 09:16:27 +0000 |
| commit | ee86f96ba176f598d64dc9f3bb7e074d5b8b86b6 (patch) | |
| tree | 31e632ae31b54ae25e9323bb51fe507e31d140ed /library/core/src/array | |
| parent | 95fb1315217976ff4c268bb03c9b4132f0dfa9fd (diff) | |
| parent | d0644947a3b093bfc09452ecd14291cea5dd8f14 (diff) | |
| download | rust-ee86f96ba176f598d64dc9f3bb7e074d5b8b86b6.tar.gz rust-ee86f96ba176f598d64dc9f3bb7e074d5b8b86b6.zip | |
Auto merge of #85828 - scottmcm:raw-eq, r=oli-obk
Stop generating `alloca`s & `memcmp` for simple short array equality
Example:
```rust
pub fn demo(x: [u16; 6], y: [u16; 6]) -> bool { x == y }
```
Before:
```llvm
define zeroext i1 `@_ZN10playground4demo17h48537f7eac23948fE(i96` %0, i96 %1) unnamed_addr #0 {
start:
%y = alloca [6 x i16], align 8
%x = alloca [6 x i16], align 8
%.0..sroa_cast = bitcast [6 x i16]* %x to i96*
store i96 %0, i96* %.0..sroa_cast, align 8
%.0..sroa_cast3 = bitcast [6 x i16]* %y to i96*
store i96 %1, i96* %.0..sroa_cast3, align 8
%_11.i.i.i = bitcast [6 x i16]* %x to i8*
%_14.i.i.i = bitcast [6 x i16]* %y to i8*
%bcmp.i.i.i = call i32 `@bcmp(i8*` nonnull dereferenceable(12) %_11.i.i.i, i8* nonnull dereferenceable(12) %_14.i.i.i, i64 12) #2, !alias.scope !2
%2 = icmp eq i32 %bcmp.i.i.i, 0
ret i1 %2
}
```
```x86
playground::demo: # `@playground::demo`
sub rsp, 32
mov qword ptr [rsp], rdi
mov dword ptr [rsp + 8], esi
mov qword ptr [rsp + 16], rdx
mov dword ptr [rsp + 24], ecx
xor rdi, rdx
xor esi, ecx
or rsi, rdi
sete al
add rsp, 32
ret
```
After:
```llvm
define zeroext i1 `@_ZN4mini4demo17h7a8994aaa314c981E(i96` %0, i96 %1) unnamed_addr #0 {
start:
%2 = icmp eq i96 %0, %1
ret i1 %2
}
```
```x86
_ZN4mini4demo17h7a8994aaa314c981E:
xor rcx, r8
xor edx, r9d
or rdx, rcx
sete al
ret
```
Diffstat (limited to 'library/core/src/array')
| -rw-r--r-- | library/core/src/array/equality.rs | 160 | ||||
| -rw-r--r-- | library/core/src/array/mod.rs | 113 |
2 files changed, 161 insertions, 112 deletions
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs new file mode 100644 index 00000000000..6d66b9e2f27 --- /dev/null +++ b/library/core/src/array/equality.rs @@ -0,0 +1,160 @@ +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &[B; N]) -> bool { + SpecArrayEq::spec_eq(self, other) + } + #[inline] + fn ne(&self, other: &[B; N]) -> bool { + SpecArrayEq::spec_ne(self, other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[B]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &[B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[B]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[A; N]> for [B] +where + B: PartialEq<A>, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<&[B]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &&[B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &&[B]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[A; N]> for &[B] +where + B: PartialEq<A>, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<&mut [B]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &&mut [B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &&mut [B]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[A; N]> for &mut [B] +where + B: PartialEq<A>, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } +} + +// NOTE: some less important impls are omitted to reduce code bloat +// __impl_slice_eq2! { [A; $N], &'b [B; $N] } +// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: Eq, const N: usize> Eq for [T; N] {} + +trait SpecArrayEq<Other, const N: usize>: Sized { + fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool; + fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool; +} + +impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T { + default fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool { + a[..] == b[..] + } + default fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool { + a[..] != b[..] + } +} + +impl<T: PartialEq<U> + IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T { + #[cfg(bootstrap)] + fn spec_eq(a: &[T; N], b: &[U; N]) -> bool { + a[..] == b[..] + } + #[cfg(not(bootstrap))] + fn spec_eq(a: &[T; N], b: &[U; N]) -> bool { + // SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`. + unsafe { + let b = &*b.as_ptr().cast::<[T; N]>(); + crate::intrinsics::raw_eq(a, b) + } + } + fn spec_ne(a: &[T; N], b: &[U; N]) -> bool { + !Self::spec_eq(a, b) + } +} + +/// `U` exists on here mostly because `min_specialization` didn't let me +/// repeat the `T` type parameter in the above specialization, so instead +/// the `T == U` constraint comes from the impls on this. +/// # Safety +/// - Neither `Self` nor `U` has any padding. +/// - `Self` and `U` have the same layout. +/// - `Self: PartialEq<U>` is byte-wise (this means no floats, among other things) +#[rustc_specialization_trait] +unsafe trait IsRawEqComparable<U> {} + +macro_rules! is_raw_comparable { + ($($t:ty),+) => {$( + unsafe impl IsRawEqComparable<$t> for $t {} + )+}; +} +is_raw_comparable!(bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 030b42a53d0..32d344010aa 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -14,6 +14,7 @@ use crate::mem::{self, MaybeUninit}; use crate::ops::{Index, IndexMut}; use crate::slice::{Iter, IterMut}; +mod equality; mod iter; #[stable(feature = "array_value_iter", since = "1.51.0")] @@ -231,118 +232,6 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &[B; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[B; N]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[B]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &[B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[B]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[A; N]> for [B] -where - B: PartialEq<A>, -{ - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<&[B]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &&[B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &&[B]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[A; N]> for &[B] -where - B: PartialEq<A>, -{ - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<&mut [B]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &&mut [B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &&mut [B]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[A; N]> for &mut [B] -where - B: PartialEq<A>, -{ - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } -} - -// NOTE: some less important impls are omitted to reduce code bloat -// __impl_slice_eq2! { [A; $N], &'b [B; $N] } -// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: Eq, const N: usize> Eq for [T; N] {} - -#[stable(feature = "rust1", since = "1.0.0")] impl<T: PartialOrd, const N: usize> PartialOrd for [T; N] { #[inline] fn partial_cmp(&self, other: &[T; N]) -> Option<Ordering> { |
