diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 6beaac9d38284..a0d9e9a72386c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1754,6 +1754,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(note); } + if let ty::Adt(adt_def, _) = rcvr_ty.kind() { + unsatisfied_predicates.iter().find(|(pred, _parent, _cause)| { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + pred.kind().skip_binder() + { + self.suggest_hashmap_on_unsatisfied_hashset_buildhasher( + err, &pred, *adt_def, + ) + } else { + false + } + }); + } + *suggested_derive = self.suggest_derive(err, unsatisfied_predicates); *unsatisfied_bounds = true; } @@ -2990,7 +3004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { match pred.self_ty().kind() { - ty::Adt(_, _) => Some(pred), + ty::Adt(_, _) => Some((e.root_obligation.predicate, pred)), _ => None, } } @@ -3000,7 +3014,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Note for local items and foreign items respectively. let (mut local_preds, mut foreign_preds): (Vec<_>, Vec<_>) = - preds.iter().partition(|&pred| { + preds.iter().partition(|&(_, pred)| { if let ty::Adt(def, _) = pred.self_ty().kind() { def.did().is_local() } else { @@ -3008,10 +3022,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }); - local_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string()); + local_preds.sort_by_key(|(_, pred)| pred.trait_ref.to_string()); let local_def_ids = local_preds .iter() - .filter_map(|pred| match pred.self_ty().kind() { + .filter_map(|(_, pred)| match pred.self_ty().kind() { ty::Adt(def, _) => Some(def.did()), _ => None, }) @@ -3024,7 +3038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect::>() .into(); - for pred in &local_preds { + for (_, pred) in &local_preds { if let ty::Adt(def, _) = pred.self_ty().kind() { local_spans.push_span_label( self.tcx.def_span(def.did()), @@ -3033,7 +3047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if local_spans.primary_span().is_some() { - let msg = if let [local_pred] = local_preds.as_slice() { + let msg = if let [(_, local_pred)] = local_preds.as_slice() { format!( "an implementation of `{}` might be missing for `{}`", local_pred.trait_ref.print_trait_sugared(), @@ -3051,9 +3065,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_note(local_spans, msg); } - foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string()); + foreign_preds + .sort_by_key(|(_, pred): &(_, ty::TraitPredicate<'_>)| pred.trait_ref.to_string()); - for pred in foreign_preds { + for (_, pred) in &foreign_preds { let ty = pred.self_ty(); let ty::Adt(def, _) = ty.kind() else { continue }; let span = self.tcx.def_span(def.did()); @@ -3066,6 +3081,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mspan, format!("`{ty}` does not implement `{}`", pred.trait_ref.print_trait_sugared()), ); + + foreign_preds.iter().find(|&(root_pred, pred)| { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(root_pred)) = + root_pred.kind().skip_binder() + && let Some(root_adt) = root_pred.self_ty().ty_adt_def() + { + self.suggest_hashmap_on_unsatisfied_hashset_buildhasher(err, pred, root_adt) + } else { + false + } + }); } let preds: Vec<_> = errors @@ -4388,6 +4414,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.autoderef(span, rcvr_ty).silence_errors().any(|(ty, _)| is_local(ty)) } + + fn suggest_hashmap_on_unsatisfied_hashset_buildhasher( + &self, + err: &mut Diag<'_>, + pred: &ty::TraitPredicate<'_>, + adt: ty::AdtDef<'_>, + ) -> bool { + if self.tcx.is_diagnostic_item(sym::HashSet, adt.did()) + && self.tcx.is_diagnostic_item(sym::BuildHasher, pred.def_id()) + { + err.help("you might have intended to use a HashMap instead"); + true + } else { + false + } + } } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index 45c32bfd1d5c5..cfb2a7fb61864 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -124,6 +124,11 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { return; }; + // This check needs to avoid ICE from when `receiver_arg` is from macro expansion + // Which leads to empty span in span arithmetic below + // cc: https://github.com/rust-lang/rust/issues/147408 + let span = receiver_arg.span.find_ancestor_in_same_ctxt(expr.span); + // If this expression comes from the `IntoIter::into_iter` inside of a for loop, // we should just suggest removing the `.into_iter()` or changing it to `.iter()` // to disambiguate if we want to iterate by-value or by-ref. @@ -134,14 +139,15 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { && let hir::ExprKind::Call(path, [_]) = &arg.kind && let hir::ExprKind::Path(qpath) = path.kind && cx.tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter) + && let Some(span) = span { Some(ShadowedIntoIterDiagSub::RemoveIntoIter { - span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + span: span.shrink_to_hi().to(expr.span.shrink_to_hi()), }) - } else if can_suggest_ufcs { + } else if can_suggest_ufcs && let Some(span) = span { Some(ShadowedIntoIterDiagSub::UseExplicitIntoIter { start_span: expr.span.shrink_to_lo(), - end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + end_span: span.shrink_to_hi().to(expr.span.shrink_to_hi()), }) } else { None diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8ab8181833064..eca4259efa7d1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -191,6 +191,7 @@ symbols! { Borrow, BorrowMut, Break, + BuildHasher, C, CStr, C_dash_unwind: "C-unwind", diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index d094172b07659..8f435dd72d7a1 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -23,6 +23,7 @@ optimize_for_size = [] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = [] +llvm_enzyme = [] [lints.rust.unexpected_cfgs] level = "warn" @@ -38,4 +39,6 @@ check-cfg = [ 'cfg(target_has_reliable_f16_math)', 'cfg(target_has_reliable_f128)', 'cfg(target_has_reliable_f128_math)', + 'cfg(llvm_enzyme)', + ] diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index a10c85640bbb6..c3f3cd7294254 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -633,6 +633,7 @@ impl Hasher for &mut H { /// /// [`build_hasher`]: BuildHasher::build_hasher /// [`HashMap`]: ../../std/collections/struct.HashMap.html +#[cfg_attr(not(test), rustc_diagnostic_item = "BuildHasher")] #[stable(since = "1.7.0", feature = "build_hasher")] pub trait BuildHasher { /// Type of the hasher that will be created. diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index c56e04bfc2d90..722a765cd01ee 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -64,21 +64,21 @@ pub unsafe fn simd_extract_dyn(x: T, idx: u32) -> U { /// `T` must be a vector of integers or floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_add(x: T, y: T) -> T; +pub const unsafe fn simd_add(x: T, y: T) -> T; /// Subtracts `rhs` from `lhs` elementwise. /// /// `T` must be a vector of integers or floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_sub(lhs: T, rhs: T) -> T; +pub const unsafe fn simd_sub(lhs: T, rhs: T) -> T; /// Multiplies two simd vectors elementwise. /// /// `T` must be a vector of integers or floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_mul(x: T, y: T) -> T; +pub const unsafe fn simd_mul(x: T, y: T) -> T; /// Divides `lhs` by `rhs` elementwise. /// @@ -89,7 +89,7 @@ pub unsafe fn simd_mul(x: T, y: T) -> T; /// Additionally for signed integers, `::MIN / -1` is undefined behavior. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_div(lhs: T, rhs: T) -> T; +pub const unsafe fn simd_div(lhs: T, rhs: T) -> T; /// Returns remainder of two vectors elementwise. /// @@ -100,7 +100,7 @@ pub unsafe fn simd_div(lhs: T, rhs: T) -> T; /// Additionally for signed integers, `::MIN / -1` is undefined behavior. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_rem(lhs: T, rhs: T) -> T; +pub const unsafe fn simd_rem(lhs: T, rhs: T) -> T; /// Shifts vector left elementwise, with UB on overflow. /// @@ -113,7 +113,7 @@ pub unsafe fn simd_rem(lhs: T, rhs: T) -> T; /// Each element of `rhs` must be less than `::BITS`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_shl(lhs: T, rhs: T) -> T; +pub const unsafe fn simd_shl(lhs: T, rhs: T) -> T; /// Shifts vector right elementwise, with UB on overflow. /// @@ -126,7 +126,7 @@ pub unsafe fn simd_shl(lhs: T, rhs: T) -> T; /// Each element of `rhs` must be less than `::BITS`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_shr(lhs: T, rhs: T) -> T; +pub const unsafe fn simd_shr(lhs: T, rhs: T) -> T; /// Funnel Shifts vector left elementwise, with UB on overflow. /// @@ -143,7 +143,7 @@ pub unsafe fn simd_shr(lhs: T, rhs: T) -> T; /// Each element of `shift` must be less than `::BITS`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_funnel_shl(a: T, b: T, shift: T) -> T; +pub const unsafe fn simd_funnel_shl(a: T, b: T, shift: T) -> T; /// Funnel Shifts vector right elementwise, with UB on overflow. /// @@ -160,28 +160,28 @@ pub unsafe fn simd_funnel_shl(a: T, b: T, shift: T) -> T; /// Each element of `shift` must be less than `::BITS`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_funnel_shr(a: T, b: T, shift: T) -> T; +pub const unsafe fn simd_funnel_shr(a: T, b: T, shift: T) -> T; /// "And"s vectors elementwise. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_and(x: T, y: T) -> T; +pub const unsafe fn simd_and(x: T, y: T) -> T; /// "Ors" vectors elementwise. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_or(x: T, y: T) -> T; +pub const unsafe fn simd_or(x: T, y: T) -> T; /// "Exclusive ors" vectors elementwise. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_xor(x: T, y: T) -> T; +pub const unsafe fn simd_xor(x: T, y: T) -> T; /// Numerically casts a vector, elementwise. /// @@ -202,7 +202,7 @@ pub unsafe fn simd_xor(x: T, y: T) -> T; /// * Be representable in the return type, after truncating off its fractional part #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_cast(x: T) -> U; +pub const unsafe fn simd_cast(x: T) -> U; /// Numerically casts a vector, elementwise. /// @@ -216,7 +216,7 @@ pub unsafe fn simd_cast(x: T) -> U; /// Otherwise, truncates or extends the value, maintaining the sign for signed integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_as(x: T) -> U; +pub const unsafe fn simd_as(x: T) -> U; /// Negates a vector elementwise. /// @@ -225,14 +225,14 @@ pub unsafe fn simd_as(x: T) -> U; /// Rust panics for `-::Min` due to overflow, but it is not UB with this intrinsic. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_neg(x: T) -> T; +pub const unsafe fn simd_neg(x: T) -> T; /// Returns absolute value of a vector, elementwise. /// /// `T` must be a vector of floating-point primitive types. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_fabs(x: T) -> T; +pub const unsafe fn simd_fabs(x: T) -> T; /// Returns the minimum of two vectors, elementwise. /// @@ -241,7 +241,7 @@ pub unsafe fn simd_fabs(x: T) -> T; /// Follows IEEE-754 `minNum` semantics. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_fmin(x: T, y: T) -> T; +pub const unsafe fn simd_fmin(x: T, y: T) -> T; /// Returns the maximum of two vectors, elementwise. /// @@ -250,7 +250,7 @@ pub unsafe fn simd_fmin(x: T, y: T) -> T; /// Follows IEEE-754 `maxNum` semantics. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_fmax(x: T, y: T) -> T; +pub const unsafe fn simd_fmax(x: T, y: T) -> T; /// Tests elementwise equality of two vectors. /// @@ -261,7 +261,7 @@ pub unsafe fn simd_fmax(x: T, y: T) -> T; /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_eq(x: T, y: T) -> U; +pub const unsafe fn simd_eq(x: T, y: T) -> U; /// Tests elementwise inequality equality of two vectors. /// @@ -272,7 +272,7 @@ pub unsafe fn simd_eq(x: T, y: T) -> U; /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_ne(x: T, y: T) -> U; +pub const unsafe fn simd_ne(x: T, y: T) -> U; /// Tests if `x` is less than `y`, elementwise. /// @@ -283,7 +283,7 @@ pub unsafe fn simd_ne(x: T, y: T) -> U; /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_lt(x: T, y: T) -> U; +pub const unsafe fn simd_lt(x: T, y: T) -> U; /// Tests if `x` is less than or equal to `y`, elementwise. /// @@ -294,7 +294,7 @@ pub unsafe fn simd_lt(x: T, y: T) -> U; /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_le(x: T, y: T) -> U; +pub const unsafe fn simd_le(x: T, y: T) -> U; /// Tests if `x` is greater than `y`, elementwise. /// @@ -305,7 +305,7 @@ pub unsafe fn simd_le(x: T, y: T) -> U; /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_gt(x: T, y: T) -> U; +pub const unsafe fn simd_gt(x: T, y: T) -> U; /// Tests if `x` is greater than or equal to `y`, elementwise. /// @@ -316,7 +316,7 @@ pub unsafe fn simd_gt(x: T, y: T) -> U; /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_ge(x: T, y: T) -> U; +pub const unsafe fn simd_ge(x: T, y: T) -> U; /// Shuffles two vectors by const indices. /// @@ -332,7 +332,7 @@ pub unsafe fn simd_ge(x: T, y: T) -> U; /// of `xy`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_shuffle(x: T, y: T, idx: U) -> V; +pub const unsafe fn simd_shuffle(x: T, y: T, idx: U) -> V; /// Reads a vector of pointers. /// @@ -353,7 +353,7 @@ pub unsafe fn simd_shuffle(x: T, y: T, idx: U) -> V; /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_gather(val: T, ptr: U, mask: V) -> T; +pub const unsafe fn simd_gather(val: T, ptr: U, mask: V) -> T; /// Writes to a vector of pointers. /// @@ -377,7 +377,7 @@ pub unsafe fn simd_gather(val: T, ptr: U, mask: V) -> T; /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_scatter(val: T, ptr: U, mask: V); +pub const unsafe fn simd_scatter(val: T, ptr: U, mask: V); /// A type for alignment options for SIMD masked load/store intrinsics. #[derive(Debug, ConstParamTy, PartialEq, Eq)] @@ -412,7 +412,8 @@ pub enum SimdAlign { /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_masked_load(mask: V, ptr: U, val: T) -> T; +pub const unsafe fn simd_masked_load(mask: V, ptr: U, val: T) +-> T; /// Writes to a vector of pointers. /// @@ -433,14 +434,14 @@ pub unsafe fn simd_masked_load(mask: V, ptr: U, /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_masked_store(mask: V, ptr: U, val: T); +pub const unsafe fn simd_masked_store(mask: V, ptr: U, val: T); /// Adds two simd vectors elementwise, with saturation. /// /// `T` must be a vector of integer primitive types. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_saturating_add(x: T, y: T) -> T; +pub const unsafe fn simd_saturating_add(x: T, y: T) -> T; /// Subtracts two simd vectors elementwise, with saturation. /// @@ -449,7 +450,7 @@ pub unsafe fn simd_saturating_add(x: T, y: T) -> T; /// Subtract `rhs` from `lhs`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_saturating_sub(lhs: T, rhs: T) -> T; +pub const unsafe fn simd_saturating_sub(lhs: T, rhs: T) -> T; /// Adds elements within a vector from left to right. /// @@ -460,7 +461,7 @@ pub unsafe fn simd_saturating_sub(lhs: T, rhs: T) -> T; /// Starting with the value `y`, add the elements of `x` and accumulate. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_add_ordered(x: T, y: U) -> U; +pub const unsafe fn simd_reduce_add_ordered(x: T, y: U) -> U; /// Adds elements within a vector in arbitrary order. May also be re-associated with /// unordered additions on the inputs/outputs. @@ -481,7 +482,7 @@ pub unsafe fn simd_reduce_add_unordered(x: T) -> U; /// Starting with the value `y`, multiply the elements of `x` and accumulate. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_mul_ordered(x: T, y: U) -> U; +pub const unsafe fn simd_reduce_mul_ordered(x: T, y: U) -> U; /// Multiplies elements within a vector in arbitrary order. May also be re-associated with /// unordered additions on the inputs/outputs. @@ -501,7 +502,7 @@ pub unsafe fn simd_reduce_mul_unordered(x: T) -> U; /// `x` must contain only `0` or `!0`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_all(x: T) -> bool; +pub const unsafe fn simd_reduce_all(x: T) -> bool; /// Checks if any mask value is true. /// @@ -511,7 +512,7 @@ pub unsafe fn simd_reduce_all(x: T) -> bool; /// `x` must contain only `0` or `!0`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_any(x: T) -> bool; +pub const unsafe fn simd_reduce_any(x: T) -> bool; /// Returns the maximum element of a vector. /// @@ -522,7 +523,7 @@ pub unsafe fn simd_reduce_any(x: T) -> bool; /// For floating-point values, uses IEEE-754 `maxNum`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_max(x: T) -> U; +pub const unsafe fn simd_reduce_max(x: T) -> U; /// Returns the minimum element of a vector. /// @@ -533,7 +534,7 @@ pub unsafe fn simd_reduce_max(x: T) -> U; /// For floating-point values, uses IEEE-754 `minNum`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_min(x: T) -> U; +pub const unsafe fn simd_reduce_min(x: T) -> U; /// Logical "and"s all elements together. /// @@ -542,7 +543,7 @@ pub unsafe fn simd_reduce_min(x: T) -> U; /// `U` must be the element type of `T`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_and(x: T) -> U; +pub const unsafe fn simd_reduce_and(x: T) -> U; /// Logical "ors" all elements together. /// @@ -551,7 +552,7 @@ pub unsafe fn simd_reduce_and(x: T) -> U; /// `U` must be the element type of `T`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_or(x: T) -> U; +pub const unsafe fn simd_reduce_or(x: T) -> U; /// Logical "exclusive ors" all elements together. /// @@ -560,7 +561,7 @@ pub unsafe fn simd_reduce_or(x: T) -> U; /// `U` must be the element type of `T`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_reduce_xor(x: T) -> U; +pub const unsafe fn simd_reduce_xor(x: T) -> U; /// Truncates an integer vector to a bitmask. /// @@ -597,7 +598,7 @@ pub unsafe fn simd_reduce_xor(x: T) -> U; /// `x` must contain only `0` and `!0`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_bitmask(x: T) -> U; +pub const unsafe fn simd_bitmask(x: T) -> U; /// Selects elements from a mask. /// @@ -613,7 +614,7 @@ pub unsafe fn simd_bitmask(x: T) -> U; /// `mask` must only contain `0` and `!0`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_select(mask: M, if_true: T, if_false: T) -> T; +pub const unsafe fn simd_select(mask: M, if_true: T, if_false: T) -> T; /// Selects elements from a bitmask. /// @@ -629,7 +630,7 @@ pub unsafe fn simd_select(mask: M, if_true: T, if_false: T) -> T; /// The bitmask bit order matches `simd_bitmask`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_select_bitmask(m: M, yes: T, no: T) -> T; +pub const unsafe fn simd_select_bitmask(m: M, yes: T, no: T) -> T; /// Calculates the offset from a pointer vector elementwise, potentially /// wrapping. @@ -641,14 +642,14 @@ pub unsafe fn simd_select_bitmask(m: M, yes: T, no: T) -> T; /// Operates as if by `::wrapping_offset`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_arith_offset(ptr: T, offset: U) -> T; +pub const unsafe fn simd_arith_offset(ptr: T, offset: U) -> T; /// Casts a vector of pointers. /// /// `T` and `U` must be vectors of pointers with the same number of elements. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_cast_ptr(ptr: T) -> U; +pub const unsafe fn simd_cast_ptr(ptr: T) -> U; /// Exposes a vector of pointers as a vector of addresses. /// @@ -666,56 +667,56 @@ pub unsafe fn simd_expose_provenance(ptr: T) -> U; /// `U` must be a vector of pointers, with the same length as `T`. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_with_exposed_provenance(addr: T) -> U; +pub const unsafe fn simd_with_exposed_provenance(addr: T) -> U; /// Swaps bytes of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_bswap(x: T) -> T; +pub const unsafe fn simd_bswap(x: T) -> T; /// Reverses bits of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_bitreverse(x: T) -> T; +pub const unsafe fn simd_bitreverse(x: T) -> T; /// Counts the leading zeros of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_ctlz(x: T) -> T; +pub const unsafe fn simd_ctlz(x: T) -> T; /// Counts the number of ones in each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_ctpop(x: T) -> T; +pub const unsafe fn simd_ctpop(x: T) -> T; /// Counts the trailing zeros of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_cttz(x: T) -> T; +pub const unsafe fn simd_cttz(x: T) -> T; /// Rounds up each element to the next highest integer-valued float. /// /// `T` must be a vector of floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_ceil(x: T) -> T; +pub const unsafe fn simd_ceil(x: T) -> T; /// Rounds down each element to the next lowest integer-valued float. /// /// `T` must be a vector of floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_floor(x: T) -> T; +pub const unsafe fn simd_floor(x: T) -> T; /// Rounds each element to the closest integer-valued float. /// Ties are resolved by rounding away from 0. @@ -723,7 +724,7 @@ pub unsafe fn simd_floor(x: T) -> T; /// `T` must be a vector of floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_round(x: T) -> T; +pub const unsafe fn simd_round(x: T) -> T; /// Rounds each element to the closest integer-valued float. /// Ties are resolved by rounding to the number with an even least significant digit @@ -731,7 +732,7 @@ pub unsafe fn simd_round(x: T) -> T; /// `T` must be a vector of floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_round_ties_even(x: T) -> T; +pub const unsafe fn simd_round_ties_even(x: T) -> T; /// Returns the integer part of each element as an integer-valued float. /// In other words, non-integer values are truncated towards zero. @@ -739,7 +740,7 @@ pub unsafe fn simd_round_ties_even(x: T) -> T; /// `T` must be a vector of floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_trunc(x: T) -> T; +pub const unsafe fn simd_trunc(x: T) -> T; /// Takes the square root of each element. /// @@ -753,7 +754,7 @@ pub unsafe fn simd_fsqrt(x: T) -> T; /// `T` must be a vector of floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_fma(x: T, y: T, z: T) -> T; +pub const unsafe fn simd_fma(x: T, y: T, z: T) -> T; /// Computes `(x*y) + z` for each element, non-deterministically executing either /// a fused multiply-add or two operations with rounding of the intermediate result. @@ -768,7 +769,7 @@ pub unsafe fn simd_fma(x: T, y: T, z: T) -> T; /// `T` must be a vector of floats. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_relaxed_fma(x: T, y: T, z: T) -> T; +pub const unsafe fn simd_relaxed_fma(x: T, y: T, z: T) -> T; // Computes the sine of each element. /// diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6156525b2f599..f3386985bdf1b 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1499,6 +1499,55 @@ pub(crate) mod builtin { /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. + /// + /// ACTIVITIES might either be `Dual` or `Const`, more options will be exposed later. + /// + /// `Const` should be used on non-float arguments, or float-based arguments as an optimization + /// if we are not interested in computing the derivatives with respect to this argument. + /// + /// `Dual` can be used for float scalar values or for references, raw pointers, or other + /// indirect input arguments. It can also be used on a scalar float return value. + /// If used on a return value, the generated function will return a tuple of two float scalars. + /// If used on an input argument, a new shadow argument of the same type will be created, + /// directly following the original argument. + /// + /// ### Usage examples: + /// + /// ```rust,ignore (autodiff requires a -Z flag as well as fat-lto for testing) + /// #![feature(autodiff)] + /// use std::autodiff::*; + /// #[autodiff_forward(rb_fwd1, Dual, Const, Dual)] + /// #[autodiff_forward(rb_fwd2, Const, Dual, Dual)] + /// #[autodiff_forward(rb_fwd3, Dual, Dual, Dual)] + /// fn rosenbrock(x: f64, y: f64) -> f64 { + /// (1.0 - x).powi(2) + 100.0 * (y - x.powi(2)).powi(2) + /// } + /// #[autodiff_forward(rb_inp_fwd, Dual, Dual, Dual)] + /// fn rosenbrock_inp(x: f64, y: f64, out: &mut f64) { + /// *out = (1.0 - x).powi(2) + 100.0 * (y - x.powi(2)).powi(2); + /// } + /// + /// fn main() { + /// let x0 = rosenbrock(1.0, 3.0); // 400.0 + /// let (x1, dx1) = rb_fwd1(1.0, 1.0, 3.0); // (400.0, -800.0) + /// let (x2, dy1) = rb_fwd2(1.0, 3.0, 1.0); // (400.0, 400.0) + /// // When seeding both arguments at once the tangent return is the sum of both. + /// let (x3, dxy) = rb_fwd3(1.0, 1.0, 3.0, 1.0); // (400.0, -400.0) + /// + /// let mut out = 0.0; + /// let mut dout = 0.0; + /// rb_inp_fwd(1.0, 1.0, 3.0, 1.0, &mut out, &mut dout); + /// // (out, dout) == (400.0, -400.0) + /// } + /// ``` + /// + /// We might want to track how one input float affects one or more output floats. In this case, + /// the shadow of one input should be initialized to `1.0`, while the shadows of the other + /// inputs should be initialized to `0.0`. The shadow of the output(s) should be initialized to + /// `0.0`. After calling the generated function, the shadow of the input will be zeroed, + /// while the shadow(s) of the output(s) will contain the derivatives. Forward mode is generally + /// more efficient if we have more output floats marked as `Dual` than input floats. + /// Related information can also be found under the term "Vector-Jacobian product" (VJP). #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[allow_internal_unstable(core_intrinsics)] @@ -1518,6 +1567,60 @@ pub(crate) mod builtin { /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. + /// + /// ACTIVITIES might either be `Active`, `Duplicated` or `Const`, more options will be exposed later. + /// + /// `Active` can be used for float scalar values. + /// If used on an input, a new float will be appended to the return tuple of the generated + /// function. If the function returns a float scalar, `Active` can be used for the return as + /// well. In this case a float scalar will be appended to the argument list, it works as seed. + /// + /// `Duplicated` can be used on references, raw pointers, or other indirect input + /// arguments. It creates a new shadow argument of the same type, following the original argument. + /// A const reference or pointer argument will receive a mutable reference or pointer as shadow. + /// + /// `Const` should be used on non-float arguments, or float-based arguments as an optimization + /// if we are not interested in computing the derivatives with respect to this argument. + /// + /// ### Usage examples: + /// + /// ```rust,ignore (autodiff requires a -Z flag as well as fat-lto for testing) + /// #![feature(autodiff)] + /// use std::autodiff::*; + /// #[autodiff_reverse(rb_rev, Active, Active, Active)] + /// fn rosenbrock(x: f64, y: f64) -> f64 { + /// (1.0 - x).powi(2) + 100.0 * (y - x.powi(2)).powi(2) + /// } + /// #[autodiff_reverse(rb_inp_rev, Active, Active, Duplicated)] + /// fn rosenbrock_inp(x: f64, y: f64, out: &mut f64) { + /// *out = (1.0 - x).powi(2) + 100.0 * (y - x.powi(2)).powi(2); + /// } + /// + /// fn main() { + /// let (output1, dx1, dy1) = rb_rev(1.0, 3.0, 1.0); + /// dbg!(output1, dx1, dy1); // (400.0, -800.0, 400.0) + /// let mut output2 = 0.0; + /// let mut seed = 1.0; + /// let (dx2, dy2) = rb_inp_rev(1.0, 3.0, &mut output2, &mut seed); + /// // (dx2, dy2, output2, seed) == (-800.0, 400.0, 400.0, 0.0) + /// } + /// ``` + /// + /// + /// We often want to track how one or more input floats affect one output float. This output can + /// be a scalar return value, or a mutable reference or pointer argument. In the latter case, the + /// mutable input should be marked as duplicated and its shadow initialized to `0.0`. The shadow of + /// the output should be marked as active or duplicated and initialized to `1.0`. After calling + /// the generated function, the shadow(s) of the input(s) will contain the derivatives. The + /// shadow of the outputs ("seed") will be reset to zero. + /// If the function has more than one output float marked as active or duplicated, users might want to + /// set one of them to `1.0` and the others to `0.0` to compute partial derivatives. + /// Unlike forward-mode, a call to the generated function does not reset the shadow of the + /// inputs. + /// Reverse mode is generally more efficient if we have more active/duplicated input than + /// output floats. + /// + /// Related information can also be found under the term "Jacobian-Vector Product" (JVP). #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[allow_internal_unstable(core_intrinsics)] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 983e00e46a5f6..ee375dbaaab2d 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1781,6 +1781,33 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // SAFETY: `self.get()` can't be zero unsafe { NonZero::new_unchecked(self.get().cast_signed()) } } + + /// Returns the minimum number of bits required to represent `self`. + /// + /// # Examples + /// + /// ``` + /// #![feature(uint_bit_width)] + /// + /// # use core::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MIN.bit_width(), NonZero::new(1)?);")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0b111)?.bit_width(), NonZero::new(3)?);")] + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0b1110)?.bit_width(), NonZero::new(4)?);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "uint_bit_width", issue = "142326")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn bit_width(self) -> NonZero { + // SAFETY: Since `self.leading_zeros()` is always less than + // `Self::BITS`, this subtraction can never be zero. + unsafe { NonZero::new_unchecked(Self::BITS - self.leading_zeros()) } + } }; // Associated items for signed nonzero types only. diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 8d4210c80827d..d2dc650910f63 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -1,3 +1,4 @@ +use super::char::EscapeDebugExtArgs; use super::from_utf8_unchecked; use super::validations::utf8_char_width; use crate::fmt; @@ -121,7 +122,11 @@ impl fmt::Debug for Debug<'_> { let valid = chunk.valid(); let mut from = 0; for (i, c) in valid.char_indices() { - let esc = c.escape_debug(); + let esc = c.escape_debug_ext(EscapeDebugExtArgs { + escape_grapheme_extended: true, + escape_single_quote: false, + escape_double_quote: true, + }); // If char needs escaping, flush backlog so far and write, else skip if esc.len() != 1 { f.write_str(&valid[from..i])?; diff --git a/library/core/src/wtf8.rs b/library/core/src/wtf8.rs index b64fccedc19cd..7214918db6c39 100644 --- a/library/core/src/wtf8.rs +++ b/library/core/src/wtf8.rs @@ -19,7 +19,7 @@ // implementations, so, we'll have to add more doc(hidden)s anyway #![doc(hidden)] -use crate::char::encode_utf16_raw; +use crate::char::{EscapeDebugExtArgs, encode_utf16_raw}; use crate::clone::CloneToUninit; use crate::fmt::{self, Write}; use crate::hash::{Hash, Hasher}; @@ -144,14 +144,20 @@ impl AsRef<[u8]> for Wtf8 { impl fmt::Debug for Wtf8 { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result { - use crate::fmt::Write; - for c in s.chars().flat_map(|c| c.escape_debug()) { + use crate::fmt::Write as _; + for c in s.chars().flat_map(|c| { + c.escape_debug_ext(EscapeDebugExtArgs { + escape_grapheme_extended: true, + escape_single_quote: false, + escape_double_quote: true, + }) + }) { f.write_char(c)? } Ok(()) } - formatter.write_str("\"")?; + formatter.write_char('"')?; let mut pos = 0; while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { // SAFETY: next_surrogate provides an index for a range of valid UTF-8 bytes. @@ -164,7 +170,7 @@ impl fmt::Debug for Wtf8 { // SAFETY: after next_surrogate returns None, the remainder is valid UTF-8. write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?; - formatter.write_str("\"") + formatter.write_char('"') } } diff --git a/library/coretests/tests/nonzero.rs b/library/coretests/tests/nonzero.rs index 69e4ed9c36b3a..c368a2621740b 100644 --- a/library/coretests/tests/nonzero.rs +++ b/library/coretests/tests/nonzero.rs @@ -570,3 +570,21 @@ fn test_nonzero_lowest_one() { nonzero_int_impl!(i8, i16, i32, i64, i128, isize); nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); } + +#[test] +fn test_nonzero_bit_width() { + macro_rules! nonzero_uint_impl { + ($($T:ty),+) => { + $( + { + assert_eq!(NonZero::<$T>::new(0b010_1100).unwrap().bit_width(), NonZero::new(6).unwrap()); + assert_eq!(NonZero::<$T>::new(0b111_1001).unwrap().bit_width(), NonZero::new(7).unwrap()); + assert_eq!(NonZero::<$T>::MIN.bit_width(), NonZero::new(1).unwrap()); + assert_eq!(NonZero::<$T>::MAX.bit_width(), NonZero::new(<$T>::BITS).unwrap()); + } + )+ + }; + } + + nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); +} diff --git a/library/coretests/tests/str_lossy.rs b/library/coretests/tests/str_lossy.rs index 6e70ea3e28574..820da38dd7466 100644 --- a/library/coretests/tests/str_lossy.rs +++ b/library/coretests/tests/str_lossy.rs @@ -80,4 +80,5 @@ fn debug() { b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa".utf8_chunks().debug(), ), ); + assert_eq!("\"'\"", &format!("{:?}", b"'".utf8_chunks().debug())); } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 685c2cf162abd..1ba9f7e32d91a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -126,6 +126,7 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] # a borrow error occurs debug_refcell = ["core/debug_refcell"] +llvm_enzyme = ["core/llvm_enzyme"] # Enable std_detect features: std_detect_file_io = ["std_detect/std_detect_file_io"] diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 6d716bd854433..fd662e8a663a9 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -170,7 +170,7 @@ impl Iterator for Vars { impl fmt::Debug for Vars { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { inner: VarsOs { inner } } = self; - f.debug_struct("Vars").field("inner", &inner.str_debug()).finish() + f.debug_struct("Vars").field("inner", inner).finish() } } diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs index 2572b71fd9ac6..3474f0ab50684 100644 --- a/library/std/src/ffi/os_str/tests.rs +++ b/library/std/src/ffi/os_str/tests.rs @@ -303,3 +303,9 @@ fn clone_to_uninit() { unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; assert_eq!(a, &*b); } + +#[test] +fn debug() { + let s = "'single quotes'"; + assert_eq!(format!("{:?}", OsStr::new(s)), format!("{:?}", s)); +} diff --git a/library/std/src/sys/env/common.rs b/library/std/src/sys/env/common.rs index f161ff073f3d5..87e86e2947fad 100644 --- a/library/std/src/sys/env/common.rs +++ b/library/std/src/sys/env/common.rs @@ -5,27 +5,10 @@ pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, } -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list() - .entries(self.slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - impl Env { pub(super) fn new(env: Vec<(OsString, OsString)>) -> Self { Env { iter: env.into_iter() } } - - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - EnvStrDebug { slice: self.iter.as_slice() } - } } impl fmt::Debug for Env { diff --git a/library/std/src/sys/env/unsupported.rs b/library/std/src/sys/env/unsupported.rs index 98905e6482747..a967ace95f02a 100644 --- a/library/std/src/sys/env/unsupported.rs +++ b/library/std/src/sys/env/unsupported.rs @@ -3,13 +3,6 @@ use crate::{fmt, io}; pub struct Env(!); -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - self.0 - } -} - impl fmt::Debug for Env { fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { self.0 diff --git a/library/std/src/sys/env/windows.rs b/library/std/src/sys/env/windows.rs index 3c4d4a84cfd6b..219fcc4fb43f9 100644 --- a/library/std/src/sys/env/windows.rs +++ b/library/std/src/sys/env/windows.rs @@ -8,30 +8,6 @@ pub struct Env { iter: EnvIterator, } -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - iter: &'a EnvIterator, -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - let iter: EnvIterator = (*iter).clone(); - let mut list = f.debug_list(); - for (a, b) in iter { - list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); - } - list.finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { base: _, iter } = self; - EnvStrDebug { iter } - } -} - impl fmt::Debug for Env { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { base: _, iter } = self; diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index ee4aec61872e7..eec8c461b6db4 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -35,3 +35,4 @@ profiler = ["dep:profiler_builtins"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] windows_raw_dylib = ["std/windows_raw_dylib"] +llvm_enzyme = ["std/llvm_enzyme"] diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 093db739e6cb2..f4f467e013258 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -846,6 +846,10 @@ impl Build { features.insert("compiler-builtins-mem"); } + if self.config.llvm_enzyme { + features.insert("llvm_enzyme"); + } + features.into_iter().collect::>().join(" ") } diff --git a/src/doc/unstable-book/src/compiler-flags/autodiff.md b/src/doc/unstable-book/src/compiler-flags/autodiff.md index 28d2ece1468f7..8d51312466bc2 100644 --- a/src/doc/unstable-book/src/compiler-flags/autodiff.md +++ b/src/doc/unstable-book/src/compiler-flags/autodiff.md @@ -6,16 +6,37 @@ The tracking issue for this feature is: [#124509](https://github.com/rust-lang/r This feature allows you to differentiate functions using automatic differentiation. Set the `-Zautodiff=` compiler flag to adjust the behaviour of the autodiff feature. -Multiple options can be separated with a comma. Valid options are: - -`Enable` - Required flag to enable autodiff -`PrintTA` - print Type Analysis Information -`PrintTAFn` - print Type Analysis Information for a specific function -`PrintAA` - print Activity Analysis Information -`PrintPerf` - print Performance Warnings from Enzyme -`PrintSteps` - prints all intermediate transformations -`PrintModBefore` - print the whole module, before running opts -`PrintModAfter` - print the module after Enzyme differentiated everything -`LooseTypes` - Enzyme's loose type debug helper (can cause incorrect gradients) -`Inline` - runs Enzyme specific Inlining -`RuntimeActivity` - allow specifying activity at runtime +Multiple options can be separated with a comma. + +## Syntax +```bash +rustc -Z autodiff=Enable[,options] +``` + +Where `options` can be: + +- `Enable` - Required flag to enable autodiff +- `PrintTA` - print Type Analysis Information +- `PrintTAFn=` - print Type Analysis Information for a specific function (consider combining it with `no_mangle`) +- `PrintAA` - print Activity Analysis Information +- `PrintPerf` - print Performance Warnings from Enzyme +- `PrintSteps` - prints all intermediate transformations +- `PrintModBefore` - print the whole module, before running opts +- `PrintModAfter` - print the module after Enzyme differentiated everything +- `LooseTypes` - Enzyme's loose type debug helper (can cause incorrect gradients) +- `Inline` - runs Enzyme specific Inlining +- `RuntimeActivity` - allow specifying activity at runtime + + +## Examples + +```bash +# Enable autodiff via cargo, assuming `enzyme` being a toolchain that supports autodiff +"RUSTFLAGS=-Zautodiff=Enable" cargo +enzyme build + +# Enable autodiff directly via rustc +rustc -Z autodiff=Enable + +# Print TypeAnalysis updates for the function `foo`, as well as Activity Analysis for all differentiated code. +rustc -Z autodiff=Enable,PrintTAFn=foo,PrintAA +``` diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index 961a4b82a7e9b..56c000633e586 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -60,7 +60,7 @@ impl PackedSimd { #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn simd_shuffle_const_generic(x: T, y: T) -> U; +pub const unsafe fn simd_shuffle_const_generic(x: T, y: T) -> U; fn simd_ops_f16() { use intrinsics::*; diff --git a/tests/auxiliary/minisimd.rs b/tests/auxiliary/minisimd.rs index ff0c996de1c87..38e2621698dbf 100644 --- a/tests/auxiliary/minisimd.rs +++ b/tests/auxiliary/minisimd.rs @@ -10,6 +10,10 @@ #![allow(unused)] #![allow(non_camel_case_types)] +// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few +// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are +// stablilized. +#![allow(unexpected_cfgs)] // The field is currently left `pub` for convenience in porting tests, many of // which attempt to just construct it directly. That still works; it's just the @@ -24,39 +28,32 @@ impl Clone for Simd { } } -impl PartialEq for Simd { - fn eq(&self, other: &Self) -> bool { - self.as_array() == other.as_array() - } -} - impl core::fmt::Debug for Simd { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { <[T; N] as core::fmt::Debug>::fmt(self.as_array(), f) } } -impl core::ops::Index for Simd { - type Output = T; - fn index(&self, i: usize) -> &T { - &self.as_array()[i] - } -} - impl Simd { pub const fn from_array(a: [T; N]) -> Self { Simd(a) } - pub fn as_array(&self) -> &[T; N] { + pub const fn as_array(&self) -> &[T; N] { let p: *const Self = self; unsafe { &*p.cast::<[T; N]>() } } - pub fn into_array(self) -> [T; N] + pub const fn into_array(self) -> [T; N] where T: Copy, { *self.as_array() } + pub const fn splat(a: T) -> Self + where + T: Copy, + { + Self([a; N]) + } } pub type u8x2 = Simd; @@ -109,6 +106,14 @@ pub type i64x8 = Simd; pub type i128x2 = Simd; pub type i128x4 = Simd; +pub type usizex2 = Simd; +pub type usizex4 = Simd; +pub type usizex8 = Simd; + +pub type isizex2 = Simd; +pub type isizex4 = Simd; +pub type isizex8 = Simd; + pub type f32x2 = Simd; pub type f32x4 = Simd; pub type f32x8 = Simd; @@ -122,7 +127,7 @@ pub type f64x8 = Simd; // which attempt to just construct it directly. That still works; it's just the // `.0` projection that doesn't. #[repr(simd, packed)] -#[derive(Copy)] +#[derive(Copy, Eq)] pub struct PackedSimd(pub [T; N]); impl Clone for PackedSimd { @@ -131,12 +136,6 @@ impl Clone for PackedSimd { } } -impl PartialEq for PackedSimd { - fn eq(&self, other: &Self) -> bool { - self.as_array() == other.as_array() - } -} - impl core::fmt::Debug for PackedSimd { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { <[T; N] as core::fmt::Debug>::fmt(self.as_array(), f) @@ -147,14 +146,81 @@ impl PackedSimd { pub const fn from_array(a: [T; N]) -> Self { PackedSimd(a) } - pub fn as_array(&self) -> &[T; N] { + pub const fn as_array(&self) -> &[T; N] { let p: *const Self = self; unsafe { &*p.cast::<[T; N]>() } } - pub fn into_array(self) -> [T; N] + pub const fn into_array(self) -> [T; N] where T: Copy, { *self.as_array() } + pub const fn splat(a: T) -> Self + where + T: Copy, + { + Self([a; N]) + } +} + +// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way +// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way +// for that is a macro + +macro_rules! impl_traits { + ($($const_:ident)?) => { + impl $($const_)? PartialEq for Simd { + fn eq(&self, other: &Self) -> bool { + self.as_array() == other.as_array() + } + } + + impl $($const_)? core::ops::Index for Simd { + type Output = T; + fn index(&self, i: usize) -> &T { + &self.as_array()[i] + } + } + + impl $($const_)? PartialEq for PackedSimd + { + fn eq(&self, other: &Self) -> bool { + self.as_array() == other.as_array() + } + } + }; } + +#[cfg(minisimd_const)] +impl_traits!(const); + +#[cfg(not(minisimd_const))] +impl_traits!(); + +/// Version of `assert_eq` that ignores fancy runtime printing in const context. +/// FIXME: Remove once is fixed. +#[cfg(minisimd_const)] +#[macro_export] +macro_rules! assert_eq { + ($left:expr, $right:expr $(,)?) => { + assert_eq!( + $left, + $right, + concat!("`", stringify!($left), "` == `", stringify!($right), "`") + ); + }; + ($left:expr, $right:expr$(, $($arg:tt)+)?) => { + { + let left = $left; + let right = $right; + // type inference works better with the concrete type on the + // left, but humans work better with the expected on the + // right + assert!(right == left, $($($arg)*),*); + } + }; +} + +#[cfg(minisimd_const)] +use assert_eq; diff --git a/tests/ui/hashmap/hashset_generics.rs b/tests/ui/hashmap/hashset_generics.rs new file mode 100644 index 0000000000000..8671066989f1f --- /dev/null +++ b/tests/ui/hashmap/hashset_generics.rs @@ -0,0 +1,20 @@ +use std::collections::HashSet; + +#[derive(PartialEq)] +//~^ NOTE in this expansion of +//~| NOTE in this expansion of +//~| NOTE in this expansion of +pub struct MyStruct { + pub parameters: HashSet, + //~^ NOTE `String` does not implement `BuildHasher` + //~| ERROR binary operation + //~| HELP use a HashMap +} + +fn main() { + let h1 = HashSet::::with_hasher(0); + h1.insert(1); + //~^ ERROR its trait bounds were not satisfied + //~| NOTE the following trait bounds + //~| HELP use a HashMap +} diff --git a/tests/ui/hashmap/hashset_generics.stderr b/tests/ui/hashmap/hashset_generics.stderr new file mode 100644 index 0000000000000..a677b6671eb8e --- /dev/null +++ b/tests/ui/hashmap/hashset_generics.stderr @@ -0,0 +1,29 @@ +error[E0369]: binary operation `==` cannot be applied to type `HashSet` + --> $DIR/hashset_generics.rs:8:5 + | +LL | #[derive(PartialEq)] + | --------- in this derive macro expansion +... +LL | pub parameters: HashSet, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `String` does not implement `BuildHasher` + --> $SRC_DIR/alloc/src/string.rs:LL:COL + | + = note: `String` is defined in another crate + = help: you might have intended to use a HashMap instead + +error[E0599]: the method `insert` exists for struct `HashSet`, but its trait bounds were not satisfied + --> $DIR/hashset_generics.rs:16:8 + | +LL | h1.insert(1); + | ^^^^^^ + | + = note: the following trait bounds were not satisfied: + `usize: BuildHasher` + = help: you might have intended to use a HashMap instead + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0369, E0599. +For more information about an error, try `rustc --explain E0369`. diff --git a/tests/ui/macros/macro-expansion-empty-span-147408.rs b/tests/ui/macros/macro-expansion-empty-span-147408.rs new file mode 100644 index 0000000000000..6df96d7b05d45 --- /dev/null +++ b/tests/ui/macros/macro-expansion-empty-span-147408.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ compile-flags: -Afor_loops_over_fallibles -Warray_into_iter + +fn main() { + macro_rules! mac { + (iter $e:expr) => { + $e.iter() + }; + (into_iter $e:expr) => { + $e.into_iter() //~ WARN this method call resolves to + //~^ WARN this changes meaning in Rust 2021 + }; + (next $e:expr) => { + $e.iter().next() + }; + } + + for _ in dbg!([1, 2]).iter() {} + for _ in dbg!([1, 2]).into_iter() {} //~ WARN this method call resolves to + //~^ WARN this changes meaning in Rust 2021 + for _ in mac!(iter [1, 2]) {} + for _ in mac!(into_iter [1, 2]) {} + for _ in mac!(next [1, 2]) {} +} diff --git a/tests/ui/macros/macro-expansion-empty-span-147408.stderr b/tests/ui/macros/macro-expansion-empty-span-147408.stderr new file mode 100644 index 0000000000000..c4faaa20101d3 --- /dev/null +++ b/tests/ui/macros/macro-expansion-empty-span-147408.stderr @@ -0,0 +1,35 @@ +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 + --> $DIR/macro-expansion-empty-span-147408.rs:19:27 + | +LL | for _ in dbg!([1, 2]).into_iter() {} + | ^^^^^^^^^ + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + = note: requested on the command line with `-W array-into-iter` +help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + | +LL - for _ in dbg!([1, 2]).into_iter() {} +LL + for _ in dbg!([1, 2]).iter() {} + | +help: or remove `.into_iter()` to iterate by value + | +LL - for _ in dbg!([1, 2]).into_iter() {} +LL + for _ in dbg!([1, 2]) {} + | + +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 + --> $DIR/macro-expansion-empty-span-147408.rs:10:16 + | +LL | $e.into_iter() + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` +... +LL | for _ in mac!(into_iter [1, 2]) {} + | ---------------------- in this macro invocation + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + = note: this warning originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 2 warnings emitted + diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs index 743aae8d1c319..8797a8a9dca49 100644 --- a/tests/ui/simd/intrinsic/float-math-pass.rs +++ b/tests/ui/simd/intrinsic/float-math-pass.rs @@ -1,6 +1,7 @@ //@ run-pass //@ ignore-emscripten //@ ignore-android +//@ compile-flags: --cfg minisimd_const // FIXME: this test fails on arm-android because the NDK version 14 is too old. // It needs at least version 18. We disable it on all android build bots because @@ -8,7 +9,7 @@ // Test that the simd floating-point math intrinsics produce correct results. -#![feature(repr_simd, intrinsics, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #![allow(non_camel_case_types)] #[path = "../../../auxiliary/minisimd.rs"] @@ -20,7 +21,10 @@ use std::intrinsics::simd::*; macro_rules! assert_approx_eq_f32 { ($a:expr, $b:expr) => {{ let (a, b) = (&$a, &$b); - assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b); + assert!( + (*a - *b).abs() < 1.0e-6, + concat!(stringify!($a), " is not approximately equal to ", stringify!($b)) + ); }}; } macro_rules! assert_approx_eq { @@ -34,7 +38,7 @@ macro_rules! assert_approx_eq { }}; } -fn main() { +const fn simple_math() { let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]); let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]); let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]); @@ -43,21 +47,44 @@ fn main() { unsafe { let r = simd_fabs(y); - assert_approx_eq!(x, r); + assert_eq!(x, r); - let r = simd_fcos(z); + // rounding functions + let r = simd_floor(h); + assert_eq!(z, r); + + let r = simd_ceil(h); + assert_eq!(x, r); + + let r = simd_round(h); + assert_eq!(x, r); + + let r = simd_round_ties_even(h); + assert_eq!(z, r); + + let r = simd_trunc(h); + assert_eq!(z, r); + + let r = simd_fma(x, h, h); assert_approx_eq!(x, r); - let r = simd_fexp(z); + let r = simd_relaxed_fma(x, h, h); assert_approx_eq!(x, r); + } +} - let r = simd_fexp2(z); +fn special_math() { + let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]); + let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]); + + unsafe { + let r = simd_fcos(z); assert_approx_eq!(x, r); - let r = simd_fma(x, h, h); + let r = simd_fexp(z); assert_approx_eq!(x, r); - let r = simd_relaxed_fma(x, h, h); + let r = simd_fexp2(z); assert_approx_eq!(x, r); let r = simd_fsqrt(x); @@ -74,21 +101,11 @@ fn main() { let r = simd_fsin(z); assert_approx_eq!(z, r); - - // rounding functions - let r = simd_floor(h); - assert_eq!(z, r); - - let r = simd_ceil(h); - assert_eq!(x, r); - - let r = simd_round(h); - assert_eq!(x, r); - - let r = simd_round_ties_even(h); - assert_eq!(z, r); - - let r = simd_trunc(h); - assert_eq!(z, r); } } + +fn main() { + const { simple_math() }; + simple_math(); + special_math(); +} diff --git a/tests/ui/simd/intrinsic/float-minmax-pass.rs b/tests/ui/simd/intrinsic/float-minmax-pass.rs index 12210ba0ad120..4b6a35556ed57 100644 --- a/tests/ui/simd/intrinsic/float-minmax-pass.rs +++ b/tests/ui/simd/intrinsic/float-minmax-pass.rs @@ -1,9 +1,10 @@ //@ run-pass //@ ignore-emscripten +//@ compile-flags: --cfg minisimd_const // Test that the simd_f{min,max} intrinsics produce the correct results. -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #![allow(non_camel_case_types)] #[path = "../../../auxiliary/minisimd.rs"] @@ -12,7 +13,7 @@ use minisimd::*; use std::intrinsics::simd::*; -fn main() { +const fn minmax() { let x = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); let y = f32x4::from_array([2.0, 1.0, 4.0, 3.0]); @@ -47,3 +48,8 @@ fn main() { assert_eq!(maxn, y); } } + +fn main() { + const { minmax() }; + minmax(); +} diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs index 09f5d41a87c13..62782db37ed4c 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -1,8 +1,9 @@ //@ run-pass //@ ignore-backends: gcc +//@ compile-flags: --cfg minisimd_const #![allow(non_camel_case_types)] -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -20,7 +21,7 @@ macro_rules! all_eq { use std::intrinsics::simd::*; -fn main() { +const fn arithmetic() { let x1 = i32x4::from_array([1, 2, 3, 4]); let y1 = U32::<4>::from_array([1, 2, 3, 4]); let z1 = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); @@ -224,3 +225,8 @@ fn main() { all_eq!(simd_cttz(y1), U32::<4>::from_array([0, 1, 0, 2])); } } + +fn main() { + const { arithmetic() }; + arithmetic(); +} diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs index a997f12370347..f139bf3220102 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs @@ -1,8 +1,9 @@ //@ run-pass //@ ignore-emscripten +//@ compile-flags: --cfg minisimd_const #![allow(non_camel_case_types)] -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; type I32 = Simd; -fn main() { +const fn saturating() { // unsigned { const M: u32 = u32::MAX; @@ -84,3 +85,8 @@ fn main() { } } } + +fn main() { + const { saturating() }; + saturating(); +} diff --git a/tests/ui/simd/intrinsic/generic-as.rs b/tests/ui/simd/intrinsic/generic-as.rs index bba712e62966a..b81402e9dca4d 100644 --- a/tests/ui/simd/intrinsic/generic-as.rs +++ b/tests/ui/simd/intrinsic/generic-as.rs @@ -1,7 +1,8 @@ //@ run-pass //@ ignore-backends: gcc +//@ compile-flags: --cfg minisimd_const -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -11,7 +12,7 @@ use std::intrinsics::simd::simd_as; type V = Simd; -fn main() { +const fn as_simd() { unsafe { let u: V:: = Simd([u32::MIN, u32::MAX]); let i: V = simd_as(u); @@ -47,3 +48,8 @@ fn main() { assert_eq!(u[1], f[1] as usize); } } + +fn main() { + const { as_simd() }; + as_simd(); +} diff --git a/tests/ui/simd/intrinsic/generic-bitmask-pass.rs b/tests/ui/simd/intrinsic/generic-bitmask-pass.rs index cb3221e21d530..afe96de63becf 100644 --- a/tests/ui/simd/intrinsic/generic-bitmask-pass.rs +++ b/tests/ui/simd/intrinsic/generic-bitmask-pass.rs @@ -1,41 +1,31 @@ //@ run-pass -#![allow(non_camel_case_types)] //@ ignore-emscripten //@ ignore-endian-big behavior of simd_bitmask is endian-specific +//@ compile-flags: --cfg minisimd_const // Test that the simd_bitmask intrinsic produces correct results. -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] -use std::intrinsics::simd::simd_bitmask; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub [u32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u8x4(pub [u8; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct Tx4(pub [T; 4]); +use std::intrinsics::simd::simd_bitmask; -fn main() { - let z = u32x4([0, 0, 0, 0]); +const fn bitmask() { + let z = u32x4::from_array([0, 0, 0, 0]); let ez = 0_u8; - let o = u32x4([!0, !0, !0, !0]); + let o = u32x4::from_array([!0, !0, !0, !0]); let eo = 0b_1111_u8; - let m0 = u32x4([!0, 0, !0, 0]); + let m0 = u32x4::from_array([!0, 0, !0, 0]); let e0 = 0b_0000_0101_u8; - // Check that the MSB is extracted: - let m = u8x4([0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111]); let e = 0b_1101; // Check usize / isize - let msize: Tx4 = Tx4([usize::MAX, 0, usize::MAX, usize::MAX]); + let msize = usizex4::from_array([usize::MAX, 0, usize::MAX, usize::MAX]); unsafe { let r: u8 = simd_bitmask(z); @@ -47,10 +37,12 @@ fn main() { let r: u8 = simd_bitmask(m0); assert_eq!(r, e0); - let r: u8 = simd_bitmask(m); - assert_eq!(r, e); - let r: u8 = simd_bitmask(msize); assert_eq!(r, e); } } + +fn main() { + const { bitmask() }; + bitmask(); +} diff --git a/tests/ui/simd/intrinsic/generic-bswap-byte.rs b/tests/ui/simd/intrinsic/generic-bswap-byte.rs index d30a560b1c2ed..52015c552abaa 100644 --- a/tests/ui/simd/intrinsic/generic-bswap-byte.rs +++ b/tests/ui/simd/intrinsic/generic-bswap-byte.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] +//@ compile-flags: --cfg minisimd_const +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -8,9 +8,14 @@ use minisimd::*; use std::intrinsics::simd::simd_bswap; -fn main() { +const fn bswap() { unsafe { assert_eq!(simd_bswap(i8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]); assert_eq!(simd_bswap(u8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]); } } + +fn main() { + const { bswap() }; + bswap(); +} diff --git a/tests/ui/simd/intrinsic/generic-cast-pass.rs b/tests/ui/simd/intrinsic/generic-cast-pass.rs index 0c3b00d65bf5c..9aadb5d0008a0 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pass.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pass.rs @@ -1,6 +1,7 @@ //@ run-pass +//@ compile-flags: --cfg minisimd_const -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -12,7 +13,7 @@ use std::cmp::{max, min}; type V = Simd; -fn main() { +const fn cast() { unsafe { let u: V:: = Simd([i16::MIN as u32, i16::MAX as u32]); let i: V = simd_cast(u); @@ -56,3 +57,8 @@ fn main() { assert_eq!(u[1], f[1] as usize); } } + +fn main() { + const { cast() }; + cast(); +} diff --git a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs index 594d1d25d165c..7e50fec565651 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs @@ -1,5 +1,6 @@ //@ run-pass -#![feature(repr_simd, core_intrinsics)] +//@ compile-flags: --cfg minisimd_const +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -9,17 +10,16 @@ use std::intrinsics::simd::simd_cast; type V = Simd; -fn main() { +const fn cast_ptr_width() { let u: V:: = Simd([0, 1, 2, 3]); let uu32: V = unsafe { simd_cast(u) }; let ui64: V = unsafe { simd_cast(u) }; - for (u, (uu32, ui64)) in u - .as_array() - .iter() - .zip(uu32.as_array().iter().zip(ui64.as_array().iter())) - { - assert_eq!(*u as u32, *uu32); - assert_eq!(*u as i64, *ui64); - } + assert_eq!(uu32, V::::from_array([0, 1, 2, 3])); + assert_eq!(ui64, V::::from_array([0, 1, 2, 3])); +} + +fn main() { + const { cast_ptr_width() }; + cast_ptr_width(); } diff --git a/tests/ui/simd/intrinsic/generic-comparison-pass.rs b/tests/ui/simd/intrinsic/generic-comparison-pass.rs index 3e803e8f60327..a4d19faeeeedd 100644 --- a/tests/ui/simd/intrinsic/generic-comparison-pass.rs +++ b/tests/ui/simd/intrinsic/generic-comparison-pass.rs @@ -1,7 +1,14 @@ //@ run-pass +//@ compile-flags: --cfg minisimd_const -#![feature(repr_simd, core_intrinsics, macro_metavar_expr_concat)] -#![allow(non_camel_case_types)] +#![feature( + repr_simd, + core_intrinsics, + const_trait_impl, + const_cmp, + const_index, + macro_metavar_expr_concat +)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -25,27 +32,26 @@ macro_rules! cmp { macro_rules! tests { ($($lhs: ident, $rhs: ident;)*) => {{ $( - (|| { - cmp!(eq($lhs, $rhs)); - cmp!(ne($lhs, $rhs)); + cmp!(eq($lhs, $rhs)); + cmp!(ne($lhs, $rhs)); - // test both directions - cmp!(lt($lhs, $rhs)); - cmp!(lt($rhs, $lhs)); + // test both directions + cmp!(lt($lhs, $rhs)); + cmp!(lt($rhs, $lhs)); - cmp!(le($lhs, $rhs)); - cmp!(le($rhs, $lhs)); + cmp!(le($lhs, $rhs)); + cmp!(le($rhs, $lhs)); - cmp!(gt($lhs, $rhs)); - cmp!(gt($rhs, $lhs)); + cmp!(gt($lhs, $rhs)); + cmp!(gt($rhs, $lhs)); - cmp!(ge($lhs, $rhs)); - cmp!(ge($rhs, $lhs)); - })(); - )* + cmp!(ge($lhs, $rhs)); + cmp!(ge($rhs, $lhs)); + )* }} } -fn main() { + +const fn compare() { // 13 vs. -100 tests that we get signed vs. unsigned comparisons // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); let i1 = i32x4::from_array([10, -11, 12, 13]); @@ -89,3 +95,8 @@ fn main() { } } } + +fn main() { + const { compare() }; + compare(); +} diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index f441d992e11b7..680e0dcfd7d6a 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -1,6 +1,7 @@ //@ run-pass +//@ compile-flags: --cfg minisimd_const -#![feature(repr_simd, intrinsics, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -20,49 +21,15 @@ macro_rules! all_eq { // type inference works better with the concrete type on the // left, but humans work better with the expected on the // right. - assert!(b == a, "{:?} != {:?}", a, b); + assert!(b == a, concat!(stringify!($a), "!=", stringify!($b))); }}; } -fn main() { +fn extract_insert_dyn() { let x2 = i32x2::from_array([20, 21]); let x4 = i32x4::from_array([40, 41, 42, 43]); let x8 = i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 87]); - unsafe { - all_eq!(simd_insert(x2, 0, 100), i32x2::from_array([100, 21])); - all_eq!(simd_insert(x2, 1, 100), i32x2::from_array([20, 100])); - - all_eq!(simd_insert(x4, 0, 100), i32x4::from_array([100, 41, 42, 43])); - all_eq!(simd_insert(x4, 1, 100), i32x4::from_array([40, 100, 42, 43])); - all_eq!(simd_insert(x4, 2, 100), i32x4::from_array([40, 41, 100, 43])); - all_eq!(simd_insert(x4, 3, 100), i32x4::from_array([40, 41, 42, 100])); - - all_eq!(simd_insert(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87])); - all_eq!(simd_insert(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87])); - all_eq!(simd_insert(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87])); - all_eq!(simd_insert(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100])); - - all_eq!(simd_extract(x2, 0), 20); - all_eq!(simd_extract(x2, 1), 21); - - all_eq!(simd_extract(x4, 0), 40); - all_eq!(simd_extract(x4, 1), 41); - all_eq!(simd_extract(x4, 2), 42); - all_eq!(simd_extract(x4, 3), 43); - all_eq!(simd_extract(x8, 0), 80); - all_eq!(simd_extract(x8, 1), 81); - all_eq!(simd_extract(x8, 2), 82); - all_eq!(simd_extract(x8, 3), 83); - all_eq!(simd_extract(x8, 4), 84); - all_eq!(simd_extract(x8, 5), 85); - all_eq!(simd_extract(x8, 6), 86); - all_eq!(simd_extract(x8, 7), 87); - } unsafe { all_eq!(simd_insert_dyn(x2, 0, 100), i32x2::from_array([100, 21])); all_eq!(simd_insert_dyn(x2, 1, 100), i32x2::from_array([20, 100])); @@ -98,48 +65,83 @@ fn main() { all_eq!(simd_extract_dyn(x8, 6), 86); all_eq!(simd_extract_dyn(x8, 7), 87); } +} + +macro_rules! simd_shuffle { + ($a:expr, $b:expr, $swizzle:expr) => { + simd_shuffle($a, $b, const { SimdShuffleIdx($swizzle) }) + }; +} + +const fn swizzle() { + let x2 = i32x2::from_array([20, 21]); + let x4 = i32x4::from_array([40, 41, 42, 43]); + let x8 = i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 87]); + unsafe { + all_eq!(simd_insert(x2, 0, 100), i32x2::from_array([100, 21])); + all_eq!(simd_insert(x2, 1, 100), i32x2::from_array([20, 100])); + + all_eq!(simd_insert(x4, 0, 100), i32x4::from_array([100, 41, 42, 43])); + all_eq!(simd_insert(x4, 1, 100), i32x4::from_array([40, 100, 42, 43])); + all_eq!(simd_insert(x4, 2, 100), i32x4::from_array([40, 41, 100, 43])); + all_eq!(simd_insert(x4, 3, 100), i32x4::from_array([40, 41, 42, 100])); + + all_eq!(simd_insert(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87])); + all_eq!(simd_insert(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87])); + all_eq!(simd_insert(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87])); + all_eq!(simd_insert(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100])); + + all_eq!(simd_extract(x2, 0), 20); + all_eq!(simd_extract(x2, 1), 21); + + all_eq!(simd_extract(x4, 0), 40); + all_eq!(simd_extract(x4, 1), 41); + all_eq!(simd_extract(x4, 2), 42); + all_eq!(simd_extract(x4, 3), 43); + + all_eq!(simd_extract(x8, 0), 80); + all_eq!(simd_extract(x8, 1), 81); + all_eq!(simd_extract(x8, 2), 82); + all_eq!(simd_extract(x8, 3), 83); + all_eq!(simd_extract(x8, 4), 84); + all_eq!(simd_extract(x8, 5), 85); + all_eq!(simd_extract(x8, 6), 86); + all_eq!(simd_extract(x8, 7), 87); + } let y2 = i32x2::from_array([120, 121]); let y4 = i32x4::from_array([140, 141, 142, 143]); let y8 = i32x8::from_array([180, 181, 182, 183, 184, 185, 186, 187]); unsafe { + all_eq!(simd_shuffle!(x2, y2, [3u32, 0]), i32x2::from_array([121, 20])); + all_eq!(simd_shuffle!(x2, y2, [3u32, 0, 1, 2]), i32x4::from_array([121, 20, 21, 120])); all_eq!( - simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0]) }), - i32x2::from_array([121, 20]) - ); - all_eq!( - simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2]) }), - i32x4::from_array([121, 20, 21, 120]) - ); - all_eq!( - simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2, 1, 2, 3, 0]) }), + simd_shuffle!(x2, y2, [3u32, 0, 1, 2, 1, 2, 3, 0]), i32x8::from_array([121, 20, 21, 120, 21, 120, 121, 20]) ); + all_eq!(simd_shuffle!(x4, y4, [7u32, 2]), i32x2::from_array([143, 42])); + all_eq!(simd_shuffle!(x4, y4, [7u32, 2, 5, 0]), i32x4::from_array([143, 42, 141, 40])); all_eq!( - simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2]) }), - i32x2::from_array([143, 42]) - ); - all_eq!( - simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0]) }), - i32x4::from_array([143, 42, 141, 40]) - ); - all_eq!( - simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0, 3, 6, 4, 1]) }), + simd_shuffle!(x4, y4, [7u32, 2, 5, 0, 3, 6, 4, 1]), i32x8::from_array([143, 42, 141, 40, 43, 142, 140, 41]) ); + all_eq!(simd_shuffle!(x8, y8, [11u32, 5]), i32x2::from_array([183, 85])); + all_eq!(simd_shuffle!(x8, y8, [11u32, 5, 15, 0]), i32x4::from_array([183, 85, 187, 80])); all_eq!( - simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5]) }), - i32x2::from_array([183, 85]) - ); - all_eq!( - simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0]) }), - i32x4::from_array([183, 85, 187, 80]) - ); - all_eq!( - simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0, 3, 8, 12, 1]) }), + simd_shuffle!(x8, y8, [11u32, 5, 15, 0, 3, 8, 12, 1]), i32x8::from_array([183, 85, 187, 80, 83, 180, 184, 81]) ); } } + +fn main() { + extract_insert_dyn(); + const { swizzle() }; + swizzle(); +} diff --git a/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs index c2418c019edaf..96c1040123841 100644 --- a/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs +++ b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs @@ -1,9 +1,10 @@ //@ run-pass //@ ignore-emscripten +//@ compile-flags: --cfg minisimd_const // Test that the simd_{gather,scatter} intrinsics produce the correct results. -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #![allow(non_camel_case_types)] #[path = "../../../auxiliary/minisimd.rs"] @@ -14,48 +15,11 @@ use std::intrinsics::simd::{simd_gather, simd_scatter}; type x4 = Simd; -fn main() { - let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; - - let default = x4::from_array([-3_f32, -3., -3., -3.]); - let s_strided = x4::from_array([0_f32, 2., -3., 6.]); +fn gather_scatter_of_ptrs() { + // test modifying array of *const f32 + let x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; let mask = x4::from_array([-1_i32, -1, 0, -1]); - // reading from *const - unsafe { - let pointer = x.as_ptr(); - let pointers = - x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); - - let r_strided = simd_gather(default, pointers, mask); - - assert_eq!(r_strided, s_strided); - } - - // reading from *mut - unsafe { - let pointer = x.as_mut_ptr(); - let pointers = - x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); - - let r_strided = simd_gather(default, pointers, mask); - - assert_eq!(r_strided, s_strided); - } - - // writing to *mut - unsafe { - let pointer = x.as_mut_ptr(); - let pointers = - x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); - - let values = x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]); - simd_scatter(values, pointers, mask); - - assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); - } - - // test modifying array of *const f32 let mut y = [ &x[0] as *const f32, &x[1] as *const f32, @@ -73,8 +37,7 @@ fn main() { // reading from *const unsafe { let pointer = y.as_ptr(); - let pointers = - x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); + let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]); let r_strided = simd_gather(default, pointers, mask); @@ -84,8 +47,7 @@ fn main() { // reading from *mut unsafe { let pointer = y.as_mut_ptr(); - let pointers = - x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); + let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]); let r_strided = simd_gather(default, pointers, mask); @@ -95,8 +57,7 @@ fn main() { // writing to *mut unsafe { let pointer = y.as_mut_ptr(); - let pointers = - x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); + let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]); let values = x4::from_array([y[7], y[6], y[5], y[1]]); simd_scatter(values, pointers, mask); @@ -114,3 +75,48 @@ fn main() { assert_eq!(y, s); } } + +const fn gather_scatter() { + let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; + + let default = x4::from_array([-3_f32, -3., -3., -3.]); + let s_strided = x4::from_array([0_f32, 2., -3., 6.]); + let mask = x4::from_array([-1_i32, -1, 0, -1]); + + // reading from *const + unsafe { + let pointer = x.as_ptr(); + let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // reading from *mut + unsafe { + let pointer = x.as_mut_ptr(); + let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // writing to *mut + unsafe { + let pointer = x.as_mut_ptr(); + let pointers = x4::from_array([pointer, pointer.add(2), pointer.add(4), pointer.add(6)]); + + let values = x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]); + simd_scatter(values, pointers, mask); + + assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); + } +} + +fn main() { + const { gather_scatter() }; + gather_scatter(); + gather_scatter_of_ptrs(); +} diff --git a/tests/ui/simd/intrinsic/generic-reduction-pass.rs b/tests/ui/simd/intrinsic/generic-reduction-pass.rs index 2d5d75447b661..2c615cd729e7b 100644 --- a/tests/ui/simd/intrinsic/generic-reduction-pass.rs +++ b/tests/ui/simd/intrinsic/generic-reduction-pass.rs @@ -1,35 +1,46 @@ //@ run-pass -#![allow(non_camel_case_types)] //@ ignore-emscripten +//@ compile-flags: --cfg minisimd_const // Test that the simd_reduce_{op} intrinsics produce the correct results. -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] -use std::intrinsics::simd::*; - -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4(pub [i32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u32x4(pub [u32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub [f32; 4]); +use std::intrinsics::simd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -struct b8x4(pub [i8; 4]); -fn main() { +fn unordered() { unsafe { - let x = i32x4([1, -2, 3, 4]); + let x = i32x4::from_array([1, -2, 3, 4]); let r: i32 = simd_reduce_add_unordered(x); assert_eq!(r, 6_i32); let r: i32 = simd_reduce_mul_unordered(x); assert_eq!(r, -24_i32); + } + + unsafe { + let x = u32x4::from_array([1, 2, 3, 4]); + let r: u32 = simd_reduce_add_unordered(x); + assert_eq!(r, 10_u32); + let r: u32 = simd_reduce_mul_unordered(x); + assert_eq!(r, 24_u32); + } + + unsafe { + let x = f32x4::from_array([1., -2., 3., 4.]); + let r: f32 = simd_reduce_add_unordered(x); + assert_eq!(r, 6_f32); + let r: f32 = simd_reduce_mul_unordered(x); + assert_eq!(r, -24_f32); + } +} + +const fn ordered() { + unsafe { + let x = i32x4::from_array([1, -2, 3, 4]); let r: i32 = simd_reduce_add_ordered(x, -1); assert_eq!(r, 5_i32); let r: i32 = simd_reduce_mul_ordered(x, -1); @@ -40,7 +51,7 @@ fn main() { let r: i32 = simd_reduce_max(x); assert_eq!(r, 4_i32); - let x = i32x4([-1, -1, -1, -1]); + let x = i32x4::from_array([-1, -1, -1, -1]); let r: i32 = simd_reduce_and(x); assert_eq!(r, -1_i32); let r: i32 = simd_reduce_or(x); @@ -48,7 +59,7 @@ fn main() { let r: i32 = simd_reduce_xor(x); assert_eq!(r, 0_i32); - let x = i32x4([-1, -1, 0, -1]); + let x = i32x4::from_array([-1, -1, 0, -1]); let r: i32 = simd_reduce_and(x); assert_eq!(r, 0_i32); let r: i32 = simd_reduce_or(x); @@ -58,11 +69,7 @@ fn main() { } unsafe { - let x = u32x4([1, 2, 3, 4]); - let r: u32 = simd_reduce_add_unordered(x); - assert_eq!(r, 10_u32); - let r: u32 = simd_reduce_mul_unordered(x); - assert_eq!(r, 24_u32); + let x = u32x4::from_array([1, 2, 3, 4]); let r: u32 = simd_reduce_add_ordered(x, 1); assert_eq!(r, 11_u32); let r: u32 = simd_reduce_mul_ordered(x, 2); @@ -74,7 +81,7 @@ fn main() { assert_eq!(r, 4_u32); let t = u32::MAX; - let x = u32x4([t, t, t, t]); + let x = u32x4::from_array([t, t, t, t]); let r: u32 = simd_reduce_and(x); assert_eq!(r, t); let r: u32 = simd_reduce_or(x); @@ -82,7 +89,7 @@ fn main() { let r: u32 = simd_reduce_xor(x); assert_eq!(r, 0_u32); - let x = u32x4([t, t, 0, t]); + let x = u32x4::from_array([t, t, 0, t]); let r: u32 = simd_reduce_and(x); assert_eq!(r, 0_u32); let r: u32 = simd_reduce_or(x); @@ -92,11 +99,7 @@ fn main() { } unsafe { - let x = f32x4([1., -2., 3., 4.]); - let r: f32 = simd_reduce_add_unordered(x); - assert_eq!(r, 6_f32); - let r: f32 = simd_reduce_mul_unordered(x); - assert_eq!(r, -24_f32); + let x = f32x4::from_array([1., -2., 3., 4.]); let r: f32 = simd_reduce_add_ordered(x, 0.); assert_eq!(r, 6_f32); let r: f32 = simd_reduce_mul_ordered(x, 1.); @@ -113,22 +116,28 @@ fn main() { } unsafe { - let x = b8x4([!0, !0, !0, !0]); + let x = i8x4::from_array([!0, !0, !0, !0]); let r: bool = simd_reduce_all(x); assert_eq!(r, true); let r: bool = simd_reduce_any(x); assert_eq!(r, true); - let x = b8x4([!0, !0, 0, !0]); + let x = i8x4::from_array([!0, !0, 0, !0]); let r: bool = simd_reduce_all(x); assert_eq!(r, false); let r: bool = simd_reduce_any(x); assert_eq!(r, true); - let x = b8x4([0, 0, 0, 0]); + let x = i8x4::from_array([0, 0, 0, 0]); let r: bool = simd_reduce_all(x); assert_eq!(r, false); let r: bool = simd_reduce_any(x); assert_eq!(r, false); } } + +fn main() { + unordered(); + const { ordered() }; + ordered(); +} diff --git a/tests/ui/simd/intrinsic/generic-select-pass.rs b/tests/ui/simd/intrinsic/generic-select-pass.rs index ff2d70d6a9782..ff02955f3aca6 100644 --- a/tests/ui/simd/intrinsic/generic-select-pass.rs +++ b/tests/ui/simd/intrinsic/generic-select-pass.rs @@ -2,9 +2,10 @@ #![allow(non_camel_case_types)] //@ ignore-emscripten //@ ignore-endian-big behavior of simd_select_bitmask is endian-specific +//@ compile-flags: --cfg minisimd_const // Test that the simd_select intrinsics produces correct results. -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../../auxiliary/minisimd.rs"] mod minisimd; @@ -14,7 +15,7 @@ use std::intrinsics::simd::{simd_select, simd_select_bitmask}; type b8x4 = i8x4; -fn main() { +const fn select() { let m0 = b8x4::from_array([!0, !0, !0, !0]); let m1 = b8x4::from_array([0, 0, 0, 0]); let m2 = b8x4::from_array([!0, !0, 0, 0]); @@ -173,3 +174,8 @@ fn main() { assert_eq!(r, e); } } + +fn main() { + const { select() }; + select(); +} diff --git a/tests/ui/simd/masked-load-store.rs b/tests/ui/simd/masked-load-store.rs index f6682ad16725e..7098a4405c7fb 100644 --- a/tests/ui/simd/masked-load-store.rs +++ b/tests/ui/simd/masked-load-store.rs @@ -1,6 +1,7 @@ //@ ignore-backends: gcc +//@ compile-flags: --cfg minisimd_const //@ run-pass -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../auxiliary/minisimd.rs"] mod minisimd; @@ -8,7 +9,7 @@ use minisimd::*; use std::intrinsics::simd::{SimdAlign, simd_masked_load, simd_masked_store}; -fn main() { +const fn masked_load_store() { unsafe { let a = Simd::([0, 1, 2, 3]); let b_src = [4u8, 5, 6, 7]; @@ -37,3 +38,8 @@ fn main() { assert_eq!(&output, &[0, 1, 9, 6, u8::MAX]); } } + +fn main() { + const { masked_load_store() }; + masked_load_store(); +} diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs index 991fe0d893379..1e805b008eab5 100644 --- a/tests/ui/simd/simd-bitmask-notpow2.rs +++ b/tests/ui/simd/simd-bitmask-notpow2.rs @@ -3,8 +3,9 @@ // This should be merged into `simd-bitmask` once that's fixed. //@ ignore-endian-big //@ ignore-backends: gcc +//@ compile-flags: --cfg minisimd_const -#![feature(repr_simd, core_intrinsics)] +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../auxiliary/minisimd.rs"] mod minisimd; @@ -12,15 +13,10 @@ use minisimd::*; use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; -fn main() { +const fn bitmask() { // Non-power-of-2 multi-byte mask. #[allow(non_camel_case_types)] type i32x10 = PackedSimd; - impl i32x10 { - fn splat(x: i32) -> Self { - Self([x; 10]) - } - } unsafe { let mask = i32x10::from_array([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 }; @@ -49,11 +45,6 @@ fn main() { // Test for a mask where the next multiple of 8 is not a power of two. #[allow(non_camel_case_types)] type i32x20 = PackedSimd; - impl i32x20 { - fn splat(x: i32) -> Self { - Self([x; 20]) - } - } unsafe { let mask = i32x20::from_array([ !0, !0, 0, !0, 0, @@ -91,3 +82,8 @@ fn main() { assert_eq!(selected2, mask); } } + +fn main() { + const { bitmask() }; + bitmask(); +} diff --git a/tests/ui/simd/simd-bitmask.rs b/tests/ui/simd/simd-bitmask.rs index 609dae3647b24..281a6ffb4ddd1 100644 --- a/tests/ui/simd/simd-bitmask.rs +++ b/tests/ui/simd/simd-bitmask.rs @@ -1,5 +1,6 @@ //@run-pass -#![feature(repr_simd, core_intrinsics)] +//@ compile-flags: --cfg minisimd_const +#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #[path = "../../auxiliary/minisimd.rs"] mod minisimd; @@ -7,7 +8,7 @@ use minisimd::*; use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; -fn main() { +const fn bitmask() { unsafe { let v = Simd::([-1, 0, -1, 0]); let i: u8 = simd_bitmask(v); @@ -68,3 +69,8 @@ fn main() { assert_eq!(r.into_array(), e); } } + +fn main() { + const { bitmask() }; + bitmask(); +}