diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 55c9b4d9ba12d..c3b67ac03a3a1 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1101,40 +1101,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(res, ret.layout())); }; - raw_eq, (v lhs_ref, v rhs_ref) { - fn type_by_size(size: Size) -> Option { - Type::int(size.bits().try_into().ok()?) - } - - let size = fx.layout_of(T).layout.size; - // FIXME add and use emit_small_memcmp - let is_eq_value = - if size == Size::ZERO { - // No bytes means they're trivially equal - fx.bcx.ins().iconst(types::I8, 1) - } else if let Some(clty) = type_by_size(size) { - // Can't use `trusted` for these loads; they could be unaligned. - let mut flags = MemFlags::new(); - flags.set_notrap(); - let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0); - let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0); - let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val); - fx.bcx.ins().bint(types::I8, eq) - } else { - // Just call `memcmp` (like slices do in core) when the - // size is too large or it's not a power-of-two. - let signed_bytes = i64::try_from(size.bytes()).unwrap(); - let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes); - let params = vec![AbiParam::new(fx.pointer_type); 3]; - let returns = vec![AbiParam::new(types::I32)]; - let args = &[lhs_ref, rhs_ref, bytes_val]; - let cmp = fx.lib_call("memcmp", params, returns, args)[0]; - let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0); - fx.bcx.ins().bint(types::I8, eq) - }; - ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout())); - }; - black_box, (c a) { // FIXME implement black_box semantics ret.write_cvalue(fx, a); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 572ac559d09df..4b4846fee5e53 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -4,7 +4,7 @@ mod simd; use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; -use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error}; +use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; @@ -12,7 +12,6 @@ use rustc_middle::bug; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; use rustc_span::{Span, Symbol, symbol::kw, sym}; -use rustc_target::abi::HasDataLayout; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::PanicStrategy; @@ -268,46 +267,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } } - sym::raw_eq => { - use rustc_target::abi::Abi::*; - let tp_ty = substs.type_at(0); - let layout = self.layout_of(tp_ty).layout; - let _use_integer_compare = match layout.abi { - Scalar(_) | ScalarPair(_, _) => true, - Uninhabited | Vector { .. } => false, - Aggregate { .. } => { - // For rusty ABIs, small aggregates are actually passed - // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), - // so we re-use that same threshold here. - layout.size <= self.data_layout().pointer_size * 2 - } - }; - - let a = args[0].immediate(); - let b = args[1].immediate(); - if layout.size.bytes() == 0 { - self.const_bool(true) - } - /*else if use_integer_compare { - let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits. - let ptr_ty = self.type_ptr_to(integer_ty); - let a_ptr = self.bitcast(a, ptr_ty); - let a_val = self.load(integer_ty, a_ptr, layout.align.abi); - let b_ptr = self.bitcast(b, ptr_ty); - let b_val = self.load(integer_ty, b_ptr, layout.align.abi); - self.icmp(IntPredicate::IntEQ, a_val, b_val) - }*/ - else { - let void_ptr_type = self.context.new_type::<*const ()>(); - let a_ptr = self.bitcast(a, void_ptr_type); - let b_ptr = self.bitcast(b, void_ptr_type); - let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type); - let builtin = self.context.get_builtin_function("memcmp"); - let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); - self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) - } - } - sym::black_box => { args[0].val.store(self, result); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8672459b5da3a..43e8bcf326c48 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -604,7 +604,6 @@ impl<'ll> CodegenCx<'ll, '_> { let t_i32 = self.type_i32(); let t_i64 = self.type_i64(); let t_i128 = self.type_i128(); - let t_isize = self.type_isize(); let t_f32 = self.type_f32(); let t_f64 = self.type_f64(); @@ -816,10 +815,6 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.assume", fn(i1) -> void); ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void); - // This isn't an "LLVM intrinsic", but LLVM's optimization passes - // recognize it like one and we assume it exists in `core::slice::cmp` - ifn!("memcmp", fn(i8p, i8p, t_isize) -> t_i32); - // variadic intrinsics ifn!("llvm.va_start", fn(i8p) -> void); ifn!("llvm.va_end", fn(i8p) -> void); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index f51d014bfb39a..22fbc73dad35f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -297,43 +297,6 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } - sym::raw_eq => { - use abi::Abi::*; - let tp_ty = substs.type_at(0); - let layout = self.layout_of(tp_ty).layout; - let use_integer_compare = match layout.abi { - Scalar(_) | ScalarPair(_, _) => true, - Uninhabited | Vector { .. } => false, - Aggregate { .. } => { - // For rusty ABIs, small aggregates are actually passed - // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), - // so we re-use that same threshold here. - layout.size <= self.data_layout().pointer_size * 2 - } - }; - - let a = args[0].immediate(); - let b = args[1].immediate(); - if layout.size.bytes() == 0 { - self.const_bool(true) - } else if use_integer_compare { - let integer_ty = self.type_ix(layout.size.bits()); - let ptr_ty = self.type_ptr_to(integer_ty); - let a_ptr = self.bitcast(a, ptr_ty); - let a_val = self.load(integer_ty, a_ptr, layout.align.abi); - let b_ptr = self.bitcast(b, ptr_ty); - let b_val = self.load(integer_ty, b_ptr, layout.align.abi); - self.icmp(IntPredicate::IntEQ, a_val, b_val) - } else { - let i8p_ty = self.type_i8p(); - let a_ptr = self.bitcast(a, i8p_ty); - let b_ptr = self.bitcast(b, i8p_ty); - let n = self.const_usize(layout.size.bytes()); - let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]); - self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) - } - } - sym::black_box => { args[0].val.store(self, result); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d6f856a6f0a70..9f417b5eaa6a7 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -478,10 +478,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { throw_ub_format!("`assume` intrinsic called with `false`"); } } - sym::raw_eq => { - let result = self.raw_eq_intrinsic(&args[0], &args[1])?; - self.write_scalar(result, dest)?; - } _ => return Ok(false), } @@ -590,19 +586,4 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let bytes = std::iter::repeat(byte).take(len.bytes_usize()); self.memory.write_bytes(dst, bytes) } - - pub(crate) fn raw_eq_intrinsic( - &mut self, - lhs: &OpTy<'tcx, >::PointerTag>, - rhs: &OpTy<'tcx, >::PointerTag>, - ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; - assert!(!layout.is_unsized()); - - let lhs = self.read_pointer(lhs)?; - let rhs = self.read_pointer(rhs)?; - let lhs_bytes = self.memory.read_bytes(lhs, layout.size)?; - let rhs_bytes = self.memory.read_bytes(rhs, layout.size)?; - Ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) - } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index caf33fa5d213b..9f078cc329b73 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -13,7 +13,7 @@ use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, Variant use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::call::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, + ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, }; use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; @@ -3182,7 +3182,17 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } match arg.layout.abi { - Abi::Aggregate { .. } => {} + Abi::Aggregate { .. } => { + // Pass and return structures up to 2 pointers in size by value, + // matching `ScalarPair`. LLVM will usually pass these in 2 registers + // which is more efficient than by-ref. + let max_by_val_size = Pointer.size(self) * 2; + let size = arg.layout.size; + + if arg.layout.is_unsized() || size > max_by_val_size { + arg.make_indirect(); + } + } // This is a fun case! The gist of what this is doing is // that we want callers and callees to always agree on the @@ -3208,24 +3218,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { && self.tcx.sess.target.simd_types_indirect => { arg.make_indirect(); - return; } - _ => return, - } - - // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`. - // LLVM will usually pass these in 2 registers, which is more efficient than by-ref. - let max_by_val_size = Pointer.size(self) * 2; - let size = arg.layout.size; - - if arg.layout.is_unsized() || size > max_by_val_size { - arg.make_indirect(); - } else { - // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { kind: RegKind::Integer, size }); + _ => {} } }; fixup(&mut fn_abi.ret); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 757c430e7999c..b73eeda04aab9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1069,7 +1069,6 @@ symbols! { quote, range_inclusive_new, raw_dylib, - raw_eq, raw_identifiers, raw_ref_op, re_rebalance_coherence, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 74f6f50d41289..bc21b7ebe5ed0 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -387,13 +387,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), - sym::raw_eq => { - let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) }; - let param_ty = - tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0)); - (1, vec![param_ty; 2], tcx.types.bool) - } - sym::black_box => (1, vec![param(0)], param(0)), sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index 33f7f494e9d84..d0a8019eb2879 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -1,6 +1,4 @@ use crate::convert::TryInto; -use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; -use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[B; N]> for [A; N] @@ -9,11 +7,11 @@ where { #[inline] fn eq(&self, other: &[B; N]) -> bool { - SpecArrayEq::spec_eq(self, other) + self[..] == other[..] } #[inline] fn ne(&self, other: &[B; N]) -> bool { - SpecArrayEq::spec_ne(self, other) + self[..] != other[..] } } @@ -129,88 +127,3 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Eq for [T; N] {} - -trait SpecArrayEq: Sized { - fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool; - fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool; -} - -impl, Other, const N: usize> SpecArrayEq 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, U, const N: usize> SpecArrayEq for T { - 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` is byte-wise (this means no floats, among other things) -#[rustc_specialization_trait] -unsafe trait IsRawEqComparable: PartialEq {} - -macro_rules! is_raw_eq_comparable { - ($($t:ty),+ $(,)?) => {$( - unsafe impl IsRawEqComparable<$t> for $t {} - )+}; -} - -// SAFETY: All the ordinary integer types allow all bit patterns as distinct values -is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - -// SAFETY: bool and char have *niches*, but no *padding*, so this is sound -is_raw_eq_comparable!(bool, char); - -// SAFETY: Similarly, the non-zero types have a niche, but no undef, -// and they compare like their underlying numeric type. -is_raw_eq_comparable!( - NonZeroU8, - NonZeroU16, - NonZeroU32, - NonZeroU64, - NonZeroU128, - NonZeroUsize, - NonZeroI8, - NonZeroI16, - NonZeroI32, - NonZeroI64, - NonZeroI128, - NonZeroIsize, -); - -// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus -// are also safe to equality-compare bitwise inside an `Option`. -// The way `PartialOrd` is defined for `Option` means that this wouldn't work -// for `<` or `>` on the signed types, but since we only do `==` it's fine. -is_raw_eq_comparable!( - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, -); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b5228397f0a99..5f090e078e466 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1939,25 +1939,6 @@ extern "rust-intrinsic" { #[cfg(not(bootstrap))] pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize); - /// Determines whether the raw bytes of the two values are equal. - /// - /// This is particularly handy for arrays, since it allows things like just - /// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. - /// - /// Above some backend-decided threshold this will emit calls to `memcmp`, - /// like slice equality does, instead of causing massive code size. - /// - /// # Safety - /// - /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. - /// Note that this is a stricter criterion than just the *values* being - /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. - /// - /// (The implementation is allowed to branch on the results of comparisons, - /// which is UB if any of their inputs are `undef`.) - #[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] - pub fn raw_eq(a: &T, b: &T) -> bool; - /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box diff --git a/src/test/codegen/arg-return-value-in-reg.rs b/src/test/codegen/arg-return-value-in-reg.rs deleted file mode 100644 index a69291d47821a..0000000000000 --- a/src/test/codegen/arg-return-value-in-reg.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Check that types of up to 128 bits are passed and returned by-value instead of via pointer. - -// compile-flags: -C no-prepopulate-passes -O -// only-x86_64 - -#![crate_type = "lib"] - -pub struct S { - a: u64, - b: u32, - c: u32, -} - -// CHECK: define i128 @modify(i128{{( %0)?}}) -#[no_mangle] -pub fn modify(s: S) -> S { - S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c } -} - -#[repr(packed)] -pub struct TooBig { - a: u64, - b: u32, - c: u32, - d: u8, -} - -// CHECK: define void @m_big(%TooBig* [[ATTRS:.*sret.*]], %TooBig* [[ATTRS2:.*]] %s) -#[no_mangle] -pub fn m_big(s: TooBig) -> TooBig { - TooBig { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c, d: s.d + s.d } -} diff --git a/src/test/codegen/array-clone.rs b/src/test/codegen/array-clone.rs index 0d42963bcd2ce..7b53f2172badf 100644 --- a/src/test/codegen/array-clone.rs +++ b/src/test/codegen/array-clone.rs @@ -5,11 +5,48 @@ // CHECK-LABEL: @array_clone #[no_mangle] pub fn array_clone(a: &[u8; 2]) -> [u8; 2] { - // CHECK-NOT: getelementptr - // CHECK-NOT: load i8 - // CHECK-NOT: zext - // CHECK-NOT: shl - // CHECK: load i16 - // CHECK-NEXT: ret i16 + // CHECK: getelementptr + // CHECK-NEXT: load i8 + // CHECK-NEXT: getelementptr + // CHECK-NEXT: load i8 + // CHECK: ret [2 x i8] + a.clone() +} + +// CHECK-LABEL: @array_clone_big +#[no_mangle] +pub fn array_clone_big(a: &[u8; 16]) -> [u8; 16] { + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: getelementptr inbounds [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: insertvalue [16 x i8] + // CHECK: ret [16 x i8] a.clone() } diff --git a/src/test/codegen/array-equality.rs b/src/test/codegen/array-equality.rs index fefc232b49040..abcde15e4e80b 100644 --- a/src/test/codegen/array-equality.rs +++ b/src/test/codegen/array-equality.rs @@ -3,23 +3,15 @@ #![crate_type = "lib"] -// CHECK-LABEL: @array_eq_value -#[no_mangle] -pub fn array_eq_value(a: [u16; 6], b: [u16; 6]) -> bool { - // CHECK-NEXT: start: - // CHECK-NEXT: %2 = icmp eq i96 %0, %1 - // CHECK-NEXT: ret i1 %2 - a == b -} - // CHECK-LABEL: @array_eq_ref #[no_mangle] pub fn array_eq_ref(a: &[u16; 6], b: &[u16; 6]) -> bool { - // CHECK: start: - // CHECK: load i96, i96* %{{.+}}, align 2 - // CHECK: load i96, i96* %{{.+}}, align 2 - // CHECK: icmp eq i96 - // CHECK-NEXT: ret + // CHECK-NEXT: start: + // CHECK-NEXT: bitcast [6 x i16] + // CHECK-NEXT: bitcast [6 x i16] + // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(i8* {{.*}} dereferenceable(12) %{{.+}}, i8* {{.*}} dereferenceable(12) %{{.+}}, i64 12) + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] a == b } @@ -27,8 +19,8 @@ pub fn array_eq_ref(a: &[u16; 6], b: &[u16; 6]) -> bool { #[no_mangle] pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool { // CHECK-NEXT: start: - // CHECK-NEXT: bitcast - // CHECK-NEXT: bitcast + // CHECK-NEXT: bitcast [9 x i16] + // CHECK-NEXT: bitcast [9 x i16] // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(i8* {{.*}} dereferenceable(18) %{{.+}}, i8* {{.*}} dereferenceable(18) %{{.+}}, i64 18) // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 // CHECK-NEXT: ret i1 %[[EQ]] @@ -39,19 +31,20 @@ pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool #[no_mangle] pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool { // CHECK-NEXT: start: - // CHECK-NEXT: bitcast - // CHECK-NEXT: bitcast + // CHECK-NEXT: bitcast [1234 x i16] + // CHECK-NEXT: bitcast [1234 x i16] // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(i8* {{.*}} dereferenceable(2468) %{{.+}}, i8* {{.*}} dereferenceable(2468) %{{.+}}, i64 2468) // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 // CHECK-NEXT: ret i1 %[[EQ]] a == b } -// CHECK-LABEL: @array_eq_zero(i128 %0) +// CHECK-LABEL: @array_eq_zero #[no_mangle] pub fn array_eq_zero(x: [u16; 8]) -> bool { - // CHECK-NEXT: start: - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i128 %0, 0 + // CHECK: bitcast [8 x i16] + // CHECK-NEXT: %[[CMP:.+]] = call i32 @{{bcmp|memcmp}}(i8* {{.*}} dereferenceable(16) %{{.+}}, i8* {{.*}} dereferenceable(16) {{.+}}, i64 16) + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 // CHECK-NEXT: ret i1 %[[EQ]] x == [0; 8] } diff --git a/src/test/codegen/loads.rs b/src/test/codegen/loads.rs index 3c9ecec2cbf58..7e501444a3e07 100644 --- a/src/test/codegen/loads.rs +++ b/src/test/codegen/loads.rs @@ -12,7 +12,7 @@ pub struct Bytes { // CHECK-LABEL: @borrow #[no_mangle] pub fn borrow(x: &i32) -> &i32 { -// CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull + // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull &x; // keep variable in an alloca x } @@ -20,26 +20,14 @@ pub fn borrow(x: &i32) -> &i32 { // CHECK-LABEL: @_box #[no_mangle] pub fn _box(x: Box) -> i32 { -// CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull + // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull *x } // CHECK-LABEL: small_array_alignment -// The array is loaded as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment #[no_mangle] pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] { -// CHECK: [[VAR:%[0-9]+]] = load {{(i32, )?}}i32* %{{.*}}, align 1 -// CHECK: ret i32 [[VAR]] - x -} - -// CHECK-LABEL: small_struct_alignment -// The struct is loaded as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment -#[no_mangle] -pub fn small_struct_alignment(x: Bytes) -> Bytes { -// CHECK: [[VAR:%[0-9]+]] = load {{(i32, )?}}i32* %{{.*}}, align 1 -// CHECK: ret i32 [[VAR]] + // CHECK: [[VAR:%[0-9]+]] = load [4 x i8], [4 x i8]* %{{.*}}, align 1 + // CHECK: ret [4 x i8] [[VAR]] x } diff --git a/src/test/codegen/slice-ref-equality.rs b/src/test/codegen/slice-ref-equality.rs index c06554ecdec22..cac5e5efa5825 100644 --- a/src/test/codegen/slice-ref-equality.rs +++ b/src/test/codegen/slice-ref-equality.rs @@ -2,32 +2,12 @@ #![crate_type = "lib"] -// #71602 reported a simple array comparison just generating a loop. -// This was originally fixed by ensuring it generates a single bcmp, -// but we now generate it as a load+icmp instead. `is_zero_slice` was -// tweaked to still test the case of comparison against a slice, -// and `is_zero_array` tests the new array-specific behaviour. -// The optimization was then extended to short slice-to-array comparisons, -// so the first test here now has a long slice to still get the bcmp. - -// CHECK-LABEL: @is_zero_slice_long -#[no_mangle] -pub fn is_zero_slice_long(data: &[u8; 456]) -> bool { - // CHECK: : - // CHECK-NEXT: %{{.+}} = getelementptr {{.+}} - // CHECK-NEXT: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}}) - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - &data[..] == [0; 456] -} - // CHECK-LABEL: @is_zero_slice_short #[no_mangle] pub fn is_zero_slice_short(data: &[u8; 4]) -> bool { - // CHECK: : - // CHECK-NEXT: %[[PTR:.+]] = bitcast [4 x i8]* {{.+}} to i32* - // CHECK-NEXT: %[[LOAD:.+]] = load i32, i32* %[[PTR]], align 1 - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0 + // CHECK: getelementptr [4 x i8], [4 x i8]* + // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}} + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 // CHECK-NEXT: ret i1 %[[EQ]] &data[..] == [0; 4] } @@ -35,10 +15,10 @@ pub fn is_zero_slice_short(data: &[u8; 4]) -> bool { // CHECK-LABEL: @is_zero_array #[no_mangle] pub fn is_zero_array(data: &[u8; 4]) -> bool { - // CHECK: start: - // CHECK-NEXT: %[[PTR:.+]] = bitcast [4 x i8]* {{.+}} to i32* - // CHECK-NEXT: %[[LOAD:.+]] = load i32, i32* %[[PTR]], align 1 - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0 + // CHECK-NEXT: start: + // CHECK-NEXT: getelementptr [4 x i8], [4 x i8]* + // CHECK-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}} + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 // CHECK-NEXT: ret i1 %[[EQ]] *data == [0; 4] } diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index 17f051a5bce0a..5dda533db3023 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -11,29 +11,23 @@ pub struct Bytes { } // CHECK-LABEL: small_array_alignment -// The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment #[no_mangle] pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { -// CHECK: [[TMP:%.+]] = alloca i32 -// CHECK: %y = alloca [4 x i8] -// CHECK: store i32 %0, i32* [[TMP]] -// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8* -// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false) + // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 1 + // CHECK: %y = alloca [4 x i8], align 1 + // CHECK: store [4 x i8] %0, [4 x i8]* %y + // CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8* + // CHECK: [[TMP8:%[0-9]+]] = bitcast [4 x i8]* [[TMP]] to i8* *x = y; } // CHECK-LABEL: small_struct_alignment -// The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment #[no_mangle] pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { -// CHECK: [[TMP:%.+]] = alloca i32 -// CHECK: %y = alloca %Bytes -// CHECK: store i32 %0, i32* [[TMP]] -// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8* -// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false) + // CHECK: [[TMP:%.+]] = alloca %Bytes, align 1 + // CHECK: %y = alloca %Bytes, align 1 + // CHECK: store %Bytes %0, %Bytes* %y + // CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8* + // CHECK: [[TMP8:%[0-9]+]] = bitcast %Bytes* [[TMP]] to i8* *x = y; } diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs deleted file mode 100644 index 6205e6a6559c9..0000000000000 --- a/src/test/codegen/swap-small-types.rs +++ /dev/null @@ -1,18 +0,0 @@ -// compile-flags: -O -// only-x86_64 -// ignore-debug: the debug assertions get in the way - -#![crate_type = "lib"] - -use std::mem::swap; - -type RGB48 = [u16; 3]; - -// CHECK-LABEL: @swap_rgb48 -#[no_mangle] -pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { -// CHECK-NOT: alloca -// CHECK: load i48 -// CHECK: store i48 - swap(x, y) -} diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs index f282fd237054c..1643fd5bc656b 100644 --- a/src/test/codegen/union-abi.rs +++ b/src/test/codegen/union-abi.rs @@ -7,6 +7,8 @@ #![crate_type="lib"] #![feature(repr_simd)] +// CHECK: %UnionF32U32 = type { [1 x i32] } + #[derive(Copy, Clone)] pub enum Unhab {} @@ -46,35 +48,35 @@ pub union UnionF32{a:f32} #[no_mangle] pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } -pub union UnionF32F32{a:f32, b:f32} +pub union UnionF32F32{a: f32, b: f32} // CHECK: define float @test_UnionF32F32(float %_1) #[no_mangle] pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } -pub union UnionF32U32{a:f32, b:u32} +pub union UnionF32U32{a: f32, b: u32} -// CHECK: define i32 @test_UnionF32U32(i32{{( %0)?}}) +// CHECK: define %UnionF32U32 @test_UnionF32U32(%UnionF32U32{{( %0)?}}) #[no_mangle] pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } -pub union UnionU128{a:u128} +pub union UnionU128{a: u128} // CHECK: define i128 @test_UnionU128(i128 %_1) #[no_mangle] pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } -pub union UnionU128x2{a:(u128, u128)} +pub union UnionU128x2{a: (u128, u128)} // CHECK: define void @test_UnionU128x2(i128 %_1.0, i128 %_1.1) #[no_mangle] pub fn test_UnionU128x2(_: UnionU128x2) { loop {} } #[repr(C)] -pub union CUnionU128x2{a:(u128, u128)} +pub union CUnionU128x2{a: (u128, u128)} // CHECK: define void @test_CUnionU128x2(%CUnionU128x2* {{.*}} %_1) #[no_mangle] pub fn test_CUnionU128x2(_: CUnionU128x2) { loop {} } -pub union UnionBool { b:bool } +pub union UnionBool { b: bool } // CHECK: define zeroext i1 @test_UnionBool(i8 %b) #[no_mangle] pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } } diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.rs b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.rs deleted file mode 100644 index a205a8730a0b8..0000000000000 --- a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(core_intrinsics)] -#![feature(const_intrinsic_raw_eq)] -#![deny(const_err)] - -const BAD_RAW_EQ_CALL: bool = unsafe { - std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) -//~^ ERROR evaluation of constant value failed -}; - -pub fn main() { -} diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr deleted file mode 100644 index ff78c252731bd..0000000000000 --- a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-padding.rs:6:5 - | -LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 4 bytes of memory starting at alloc3, but 1 byte is uninitialized starting at alloc3+0x1, and this operation requires initialized memory - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const.rs b/src/test/ui/intrinsics/intrinsic-raw_eq-const.rs deleted file mode 100644 index 8ea954673020e..0000000000000 --- a/src/test/ui/intrinsics/intrinsic-raw_eq-const.rs +++ /dev/null @@ -1,27 +0,0 @@ -// run-pass - -#![feature(core_intrinsics)] -#![feature(const_intrinsic_raw_eq)] -#![deny(const_err)] - -pub fn main() { - use std::intrinsics::raw_eq; - - const RAW_EQ_I32_TRUE: bool = unsafe { raw_eq(&42_i32, &42) }; - assert!(RAW_EQ_I32_TRUE); - - const RAW_EQ_I32_FALSE: bool = unsafe { raw_eq(&4_i32, &2) }; - assert!(!RAW_EQ_I32_FALSE); - - const RAW_EQ_CHAR_TRUE: bool = unsafe { raw_eq(&'a', &'a') }; - assert!(RAW_EQ_CHAR_TRUE); - - const RAW_EQ_CHAR_FALSE: bool = unsafe { raw_eq(&'a', &'A') }; - assert!(!RAW_EQ_CHAR_FALSE); - - const RAW_EQ_ARRAY_TRUE: bool = unsafe { raw_eq(&[13_u8, 42], &[13, 42]) }; - assert!(RAW_EQ_ARRAY_TRUE); - - const RAW_EQ_ARRAY_FALSE: bool = unsafe { raw_eq(&[13_u8, 42], &[42, 13]) }; - assert!(!RAW_EQ_ARRAY_FALSE); -}