Skip to content

Commit f97aded

Browse files
committed
Revert "Stop generating allocas+memcmp for simple array equality"
This reverts commit 2456495.
1 parent 3aeb61b commit f97aded

File tree

9 files changed

+2
-223
lines changed

9 files changed

+2
-223
lines changed

compiler/rustc_codegen_llvm/src/context.rs

-5
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,6 @@ impl<'ll> CodegenCx<'ll, '_> {
604604
let t_i32 = self.type_i32();
605605
let t_i64 = self.type_i64();
606606
let t_i128 = self.type_i128();
607-
let t_isize = self.type_isize();
608607
let t_f32 = self.type_f32();
609608
let t_f64 = self.type_f64();
610609

@@ -816,10 +815,6 @@ impl<'ll> CodegenCx<'ll, '_> {
816815
ifn!("llvm.assume", fn(i1) -> void);
817816
ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void);
818817

819-
// This isn't an "LLVM intrinsic", but LLVM's optimization passes
820-
// recognize it like one and we assume it exists in `core::slice::cmp`
821-
ifn!("memcmp", fn(i8p, i8p, t_isize) -> t_i32);
822-
823818
// variadic intrinsics
824819
ifn!("llvm.va_start", fn(i8p) -> void);
825820
ifn!("llvm.va_end", fn(i8p) -> void);

compiler/rustc_codegen_llvm/src/intrinsic.rs

-37
Original file line numberDiff line numberDiff line change
@@ -297,43 +297,6 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
297297
}
298298
}
299299

300-
sym::raw_eq => {
301-
use abi::Abi::*;
302-
let tp_ty = substs.type_at(0);
303-
let layout = self.layout_of(tp_ty).layout;
304-
let use_integer_compare = match layout.abi {
305-
Scalar(_) | ScalarPair(_, _) => true,
306-
Uninhabited | Vector { .. } => false,
307-
Aggregate { .. } => {
308-
// For rusty ABIs, small aggregates are actually passed
309-
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
310-
// so we re-use that same threshold here.
311-
layout.size <= self.data_layout().pointer_size * 2
312-
}
313-
};
314-
315-
let a = args[0].immediate();
316-
let b = args[1].immediate();
317-
if layout.size.bytes() == 0 {
318-
self.const_bool(true)
319-
} else if use_integer_compare {
320-
let integer_ty = self.type_ix(layout.size.bits());
321-
let ptr_ty = self.type_ptr_to(integer_ty);
322-
let a_ptr = self.bitcast(a, ptr_ty);
323-
let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
324-
let b_ptr = self.bitcast(b, ptr_ty);
325-
let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
326-
self.icmp(IntPredicate::IntEQ, a_val, b_val)
327-
} else {
328-
let i8p_ty = self.type_i8p();
329-
let a_ptr = self.bitcast(a, i8p_ty);
330-
let b_ptr = self.bitcast(b, i8p_ty);
331-
let n = self.const_usize(layout.size.bytes());
332-
let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
333-
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
334-
}
335-
}
336-
337300
sym::black_box => {
338301
args[0].val.store(self, result);
339302

compiler/rustc_const_eval/src/interpret/intrinsics.rs

-19
Original file line numberDiff line numberDiff line change
@@ -478,10 +478,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
478478
throw_ub_format!("`assume` intrinsic called with `false`");
479479
}
480480
}
481-
sym::raw_eq => {
482-
let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
483-
self.write_scalar(result, dest)?;
484-
}
485481
_ => return Ok(false),
486482
}
487483

@@ -590,19 +586,4 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
590586
let bytes = std::iter::repeat(byte).take(len.bytes_usize());
591587
self.memory.write_bytes(dst, bytes)
592588
}
593-
594-
pub(crate) fn raw_eq_intrinsic(
595-
&mut self,
596-
lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
597-
rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
598-
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
599-
let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?;
600-
assert!(!layout.is_unsized());
601-
602-
let lhs = self.read_pointer(lhs)?;
603-
let rhs = self.read_pointer(rhs)?;
604-
let lhs_bytes = self.memory.read_bytes(lhs, layout.size)?;
605-
let rhs_bytes = self.memory.read_bytes(rhs, layout.size)?;
606-
Ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
607-
}
608589
}

compiler/rustc_span/src/symbol.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,6 @@ symbols! {
10691069
quote,
10701070
range_inclusive_new,
10711071
raw_dylib,
1072-
raw_eq,
10731072
raw_identifiers,
10741073
raw_ref_op,
10751074
re_rebalance_coherence,

compiler/rustc_typeck/src/check/intrinsic.rs

-7
Original file line numberDiff line numberDiff line change
@@ -387,13 +387,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
387387

388388
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
389389

390-
sym::raw_eq => {
391-
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
392-
let param_ty =
393-
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
394-
(1, vec![param_ty; 2], tcx.types.bool)
395-
}
396-
397390
sym::black_box => (1, vec![param(0)], param(0)),
398391

399392
sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)),

library/core/src/array/equality.rs

+2-89
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
use crate::convert::TryInto;
2-
use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
3-
use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
42

53
#[stable(feature = "rust1", since = "1.0.0")]
64
impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
@@ -9,11 +7,11 @@ where
97
{
108
#[inline]
119
fn eq(&self, other: &[B; N]) -> bool {
12-
SpecArrayEq::spec_eq(self, other)
10+
self[..] == other[..]
1311
}
1412
#[inline]
1513
fn ne(&self, other: &[B; N]) -> bool {
16-
SpecArrayEq::spec_ne(self, other)
14+
self[..] != other[..]
1715
}
1816
}
1917

@@ -129,88 +127,3 @@ where
129127

130128
#[stable(feature = "rust1", since = "1.0.0")]
131129
impl<T: Eq, const N: usize> Eq for [T; N] {}
132-
133-
trait SpecArrayEq<Other, const N: usize>: Sized {
134-
fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool;
135-
fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool;
136-
}
137-
138-
impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T {
139-
default fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool {
140-
a[..] == b[..]
141-
}
142-
default fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool {
143-
a[..] != b[..]
144-
}
145-
}
146-
147-
impl<T: IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T {
148-
fn spec_eq(a: &[T; N], b: &[U; N]) -> bool {
149-
// SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`.
150-
unsafe {
151-
let b = &*b.as_ptr().cast::<[T; N]>();
152-
crate::intrinsics::raw_eq(a, b)
153-
}
154-
}
155-
fn spec_ne(a: &[T; N], b: &[U; N]) -> bool {
156-
!Self::spec_eq(a, b)
157-
}
158-
}
159-
160-
/// `U` exists on here mostly because `min_specialization` didn't let me
161-
/// repeat the `T` type parameter in the above specialization, so instead
162-
/// the `T == U` constraint comes from the impls on this.
163-
/// # Safety
164-
/// - Neither `Self` nor `U` has any padding.
165-
/// - `Self` and `U` have the same layout.
166-
/// - `Self: PartialEq<U>` is byte-wise (this means no floats, among other things)
167-
#[rustc_specialization_trait]
168-
unsafe trait IsRawEqComparable<U>: PartialEq<U> {}
169-
170-
macro_rules! is_raw_eq_comparable {
171-
($($t:ty),+ $(,)?) => {$(
172-
unsafe impl IsRawEqComparable<$t> for $t {}
173-
)+};
174-
}
175-
176-
// SAFETY: All the ordinary integer types allow all bit patterns as distinct values
177-
is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
178-
179-
// SAFETY: bool and char have *niches*, but no *padding*, so this is sound
180-
is_raw_eq_comparable!(bool, char);
181-
182-
// SAFETY: Similarly, the non-zero types have a niche, but no undef,
183-
// and they compare like their underlying numeric type.
184-
is_raw_eq_comparable!(
185-
NonZeroU8,
186-
NonZeroU16,
187-
NonZeroU32,
188-
NonZeroU64,
189-
NonZeroU128,
190-
NonZeroUsize,
191-
NonZeroI8,
192-
NonZeroI16,
193-
NonZeroI32,
194-
NonZeroI64,
195-
NonZeroI128,
196-
NonZeroIsize,
197-
);
198-
199-
// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus
200-
// are also safe to equality-compare bitwise inside an `Option`.
201-
// The way `PartialOrd` is defined for `Option` means that this wouldn't work
202-
// for `<` or `>` on the signed types, but since we only do `==` it's fine.
203-
is_raw_eq_comparable!(
204-
Option<NonZeroU8>,
205-
Option<NonZeroU16>,
206-
Option<NonZeroU32>,
207-
Option<NonZeroU64>,
208-
Option<NonZeroU128>,
209-
Option<NonZeroUsize>,
210-
Option<NonZeroI8>,
211-
Option<NonZeroI16>,
212-
Option<NonZeroI32>,
213-
Option<NonZeroI64>,
214-
Option<NonZeroI128>,
215-
Option<NonZeroIsize>,
216-
);

library/core/src/intrinsics.rs

-19
Original file line numberDiff line numberDiff line change
@@ -1939,25 +1939,6 @@ extern "rust-intrinsic" {
19391939
#[cfg(not(bootstrap))]
19401940
pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);
19411941

1942-
/// Determines whether the raw bytes of the two values are equal.
1943-
///
1944-
/// This is particularly handy for arrays, since it allows things like just
1945-
/// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`.
1946-
///
1947-
/// Above some backend-decided threshold this will emit calls to `memcmp`,
1948-
/// like slice equality does, instead of causing massive code size.
1949-
///
1950-
/// # Safety
1951-
///
1952-
/// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized.
1953-
/// Note that this is a stricter criterion than just the *values* being
1954-
/// fully-initialized: if `T` has padding, it's UB to call this intrinsic.
1955-
///
1956-
/// (The implementation is allowed to branch on the results of comparisons,
1957-
/// which is UB if any of their inputs are `undef`.)
1958-
#[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")]
1959-
pub fn raw_eq<T>(a: &T, b: &T) -> bool;
1960-
19611942
/// See documentation of [`std::hint::black_box`] for details.
19621943
///
19631944
/// [`std::hint::black_box`]: crate::hint::black_box

src/test/codegen/slice-ref-equality.rs

-19
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,6 @@
22

33
#![crate_type = "lib"]
44

5-
// #71602 reported a simple array comparison just generating a loop.
6-
// This was originally fixed by ensuring it generates a single bcmp,
7-
// but we now generate it as a load+icmp instead. `is_zero_slice` was
8-
// tweaked to still test the case of comparison against a slice,
9-
// and `is_zero_array` tests the new array-specific behaviour.
10-
// The optimization was then extended to short slice-to-array comparisons,
11-
// so the first test here now has a long slice to still get the bcmp.
12-
13-
// CHECK-LABEL: @is_zero_slice_long
14-
#[no_mangle]
15-
pub fn is_zero_slice_long(data: &[u8; 456]) -> bool {
16-
// CHECK: :
17-
// CHECK-NEXT: %{{.+}} = getelementptr {{.+}}
18-
// CHECK-NEXT: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}})
19-
// CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0
20-
// CHECK-NEXT: ret i1 %[[EQ]]
21-
&data[..] == [0; 456]
22-
}
23-
245
// CHECK-LABEL: @is_zero_slice_short
256
#[no_mangle]
267
pub fn is_zero_slice_short(data: &[u8; 4]) -> bool {

src/test/ui/intrinsics/intrinsic-raw_eq-const.rs

-27
This file was deleted.

0 commit comments

Comments
 (0)