Auto merge of #149085 - matthiaskrgr:rollup-f8ia15e, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang/rust#147171 (recommend using a HashMap if a HashSet's second generic parameter doesn't implement BuildHasher)
 - rust-lang/rust#147421 (Add check if span is from macro expansion)
 - rust-lang/rust#147521 (Make SIMD intrinsics available in `const`-contexts)
 - rust-lang/rust#148201 (Start documenting autodiff activities)
 - rust-lang/rust#148797 (feat: Add `bit_width` for unsigned `NonZero<T>`)
 - rust-lang/rust#148798 (Match <OsString as Debug>::fmt to that of str)
 - rust-lang/rust#149082 (autodiff: update formating, improve examples for the unstable-book)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-11-19 08:54:07 +00:00
commit 140044cffa
44 changed files with 884 additions and 425 deletions

View file

@ -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::<Vec<_>>()
.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)]

View file

@ -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

View file

@ -191,6 +191,7 @@ symbols! {
Borrow,
BorrowMut,
Break,
BuildHasher,
C,
CStr,
C_dash_unwind: "C-unwind",

View file

@ -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)',
]

View file

@ -633,6 +633,7 @@ impl<H: Hasher + ?Sized> 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.

View file

@ -64,21 +64,21 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
/// `T` must be a vector of integers or floats.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_add<T>(x: T, y: T) -> T;
pub const unsafe fn simd_add<T>(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<T>(lhs: T, rhs: T) -> T;
pub const unsafe fn simd_sub<T>(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<T>(x: T, y: T) -> T;
pub const unsafe fn simd_mul<T>(x: T, y: T) -> T;
/// Divides `lhs` by `rhs` elementwise.
///
@ -89,7 +89,7 @@ pub unsafe fn simd_mul<T>(x: T, y: T) -> T;
/// Additionally for signed integers, `<int>::MIN / -1` is undefined behavior.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_div<T>(lhs: T, rhs: T) -> T;
pub const unsafe fn simd_div<T>(lhs: T, rhs: T) -> T;
/// Returns remainder of two vectors elementwise.
///
@ -100,7 +100,7 @@ pub unsafe fn simd_div<T>(lhs: T, rhs: T) -> T;
/// Additionally for signed integers, `<int>::MIN / -1` is undefined behavior.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_rem<T>(lhs: T, rhs: T) -> T;
pub const unsafe fn simd_rem<T>(lhs: T, rhs: T) -> T;
/// Shifts vector left elementwise, with UB on overflow.
///
@ -113,7 +113,7 @@ pub unsafe fn simd_rem<T>(lhs: T, rhs: T) -> T;
/// Each element of `rhs` must be less than `<int>::BITS`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_shl<T>(lhs: T, rhs: T) -> T;
pub const unsafe fn simd_shl<T>(lhs: T, rhs: T) -> T;
/// Shifts vector right elementwise, with UB on overflow.
///
@ -126,7 +126,7 @@ pub unsafe fn simd_shl<T>(lhs: T, rhs: T) -> T;
/// Each element of `rhs` must be less than `<int>::BITS`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_shr<T>(lhs: T, rhs: T) -> T;
pub const unsafe fn simd_shr<T>(lhs: T, rhs: T) -> T;
/// Funnel Shifts vector left elementwise, with UB on overflow.
///
@ -143,7 +143,7 @@ pub unsafe fn simd_shr<T>(lhs: T, rhs: T) -> T;
/// Each element of `shift` must be less than `<int>::BITS`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_funnel_shl<T>(a: T, b: T, shift: T) -> T;
pub const unsafe fn simd_funnel_shl<T>(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<T>(a: T, b: T, shift: T) -> T;
/// Each element of `shift` must be less than `<int>::BITS`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_funnel_shr<T>(a: T, b: T, shift: T) -> T;
pub const unsafe fn simd_funnel_shr<T>(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<T>(x: T, y: T) -> T;
pub const unsafe fn simd_and<T>(x: T, y: T) -> T;
/// "Ors" vectors elementwise.
///
/// `T` must be a vector of integers.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_or<T>(x: T, y: T) -> T;
pub const unsafe fn simd_or<T>(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<T>(x: T, y: T) -> T;
pub const unsafe fn simd_xor<T>(x: T, y: T) -> T;
/// Numerically casts a vector, elementwise.
///
@ -202,7 +202,7 @@ pub unsafe fn simd_xor<T>(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<T, U>(x: T) -> U;
pub const unsafe fn simd_cast<T, U>(x: T) -> U;
/// Numerically casts a vector, elementwise.
///
@ -216,7 +216,7 @@ pub unsafe fn simd_cast<T, U>(x: T) -> U;
/// Otherwise, truncates or extends the value, maintaining the sign for signed integers.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_as<T, U>(x: T) -> U;
pub const unsafe fn simd_as<T, U>(x: T) -> U;
/// Negates a vector elementwise.
///
@ -225,14 +225,14 @@ pub unsafe fn simd_as<T, U>(x: T) -> U;
/// Rust panics for `-<int>::Min` due to overflow, but it is not UB with this intrinsic.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_neg<T>(x: T) -> T;
pub const unsafe fn simd_neg<T>(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<T>(x: T) -> T;
pub const unsafe fn simd_fabs<T>(x: T) -> T;
/// Returns the minimum of two vectors, elementwise.
///
@ -241,7 +241,7 @@ pub unsafe fn simd_fabs<T>(x: T) -> T;
/// Follows IEEE-754 `minNum` semantics.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_fmin<T>(x: T, y: T) -> T;
pub const unsafe fn simd_fmin<T>(x: T, y: T) -> T;
/// Returns the maximum of two vectors, elementwise.
///
@ -250,7 +250,7 @@ pub unsafe fn simd_fmin<T>(x: T, y: T) -> T;
/// Follows IEEE-754 `maxNum` semantics.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_fmax<T>(x: T, y: T) -> T;
pub const unsafe fn simd_fmax<T>(x: T, y: T) -> T;
/// Tests elementwise equality of two vectors.
///
@ -261,7 +261,7 @@ pub unsafe fn simd_fmax<T>(x: T, y: T) -> T;
/// Returns `0` for false and `!0` for true.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_eq<T, U>(x: T, y: T) -> U;
pub const unsafe fn simd_eq<T, U>(x: T, y: T) -> U;
/// Tests elementwise inequality equality of two vectors.
///
@ -272,7 +272,7 @@ pub unsafe fn simd_eq<T, U>(x: T, y: T) -> U;
/// Returns `0` for false and `!0` for true.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_ne<T, U>(x: T, y: T) -> U;
pub const unsafe fn simd_ne<T, U>(x: T, y: T) -> U;
/// Tests if `x` is less than `y`, elementwise.
///
@ -283,7 +283,7 @@ pub unsafe fn simd_ne<T, U>(x: T, y: T) -> U;
/// Returns `0` for false and `!0` for true.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_lt<T, U>(x: T, y: T) -> U;
pub const unsafe fn simd_lt<T, U>(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<T, U>(x: T, y: T) -> U;
/// Returns `0` for false and `!0` for true.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_le<T, U>(x: T, y: T) -> U;
pub const unsafe fn simd_le<T, U>(x: T, y: T) -> U;
/// Tests if `x` is greater than `y`, elementwise.
///
@ -305,7 +305,7 @@ pub unsafe fn simd_le<T, U>(x: T, y: T) -> U;
/// Returns `0` for false and `!0` for true.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_gt<T, U>(x: T, y: T) -> U;
pub const unsafe fn simd_gt<T, U>(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<T, U>(x: T, y: T) -> U;
/// Returns `0` for false and `!0` for true.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_ge<T, U>(x: T, y: T) -> U;
pub const unsafe fn simd_ge<T, U>(x: T, y: T) -> U;
/// Shuffles two vectors by const indices.
///
@ -332,7 +332,7 @@ pub unsafe fn simd_ge<T, U>(x: T, y: T) -> U;
/// of `xy`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
pub const unsafe fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
/// Reads a vector of pointers.
///
@ -353,7 +353,7 @@ pub unsafe fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
/// `mask` must only contain `0` or `!0` values.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
pub const unsafe fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
/// Writes to a vector of pointers.
///
@ -377,7 +377,7 @@ pub unsafe fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
/// `mask` must only contain `0` or `!0` values.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
pub const unsafe fn simd_scatter<T, U, V>(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<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U, val: T) -> T;
pub const unsafe fn simd_masked_load<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U, val: T)
-> T;
/// Writes to a vector of pointers.
///
@ -433,14 +434,14 @@ pub unsafe fn simd_masked_load<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U,
/// `mask` must only contain `0` or `!0` values.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_masked_store<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U, val: T);
pub const unsafe fn simd_masked_store<V, U, T, const ALIGN: SimdAlign>(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<T>(x: T, y: T) -> T;
pub const unsafe fn simd_saturating_add<T>(x: T, y: T) -> T;
/// Subtracts two simd vectors elementwise, with saturation.
///
@ -449,7 +450,7 @@ pub unsafe fn simd_saturating_add<T>(x: T, y: T) -> T;
/// Subtract `rhs` from `lhs`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_saturating_sub<T>(lhs: T, rhs: T) -> T;
pub const unsafe fn simd_saturating_sub<T>(lhs: T, rhs: T) -> T;
/// Adds elements within a vector from left to right.
///
@ -460,7 +461,7 @@ pub unsafe fn simd_saturating_sub<T>(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<T, U>(x: T, y: U) -> U;
pub const unsafe fn simd_reduce_add_ordered<T, U>(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<T, U>(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<T, U>(x: T, y: U) -> U;
pub const unsafe fn simd_reduce_mul_ordered<T, U>(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<T, U>(x: T) -> U;
/// `x` must contain only `0` or `!0`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_reduce_all<T>(x: T) -> bool;
pub const unsafe fn simd_reduce_all<T>(x: T) -> bool;
/// Checks if any mask value is true.
///
@ -511,7 +512,7 @@ pub unsafe fn simd_reduce_all<T>(x: T) -> bool;
/// `x` must contain only `0` or `!0`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_reduce_any<T>(x: T) -> bool;
pub const unsafe fn simd_reduce_any<T>(x: T) -> bool;
/// Returns the maximum element of a vector.
///
@ -522,7 +523,7 @@ pub unsafe fn simd_reduce_any<T>(x: T) -> bool;
/// For floating-point values, uses IEEE-754 `maxNum`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_reduce_max<T, U>(x: T) -> U;
pub const unsafe fn simd_reduce_max<T, U>(x: T) -> U;
/// Returns the minimum element of a vector.
///
@ -533,7 +534,7 @@ pub unsafe fn simd_reduce_max<T, U>(x: T) -> U;
/// For floating-point values, uses IEEE-754 `minNum`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_reduce_min<T, U>(x: T) -> U;
pub const unsafe fn simd_reduce_min<T, U>(x: T) -> U;
/// Logical "and"s all elements together.
///
@ -542,7 +543,7 @@ pub unsafe fn simd_reduce_min<T, U>(x: T) -> U;
/// `U` must be the element type of `T`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_reduce_and<T, U>(x: T) -> U;
pub const unsafe fn simd_reduce_and<T, U>(x: T) -> U;
/// Logical "ors" all elements together.
///
@ -551,7 +552,7 @@ pub unsafe fn simd_reduce_and<T, U>(x: T) -> U;
/// `U` must be the element type of `T`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_reduce_or<T, U>(x: T) -> U;
pub const unsafe fn simd_reduce_or<T, U>(x: T) -> U;
/// Logical "exclusive ors" all elements together.
///
@ -560,7 +561,7 @@ pub unsafe fn simd_reduce_or<T, U>(x: T) -> U;
/// `U` must be the element type of `T`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_reduce_xor<T, U>(x: T) -> U;
pub const unsafe fn simd_reduce_xor<T, U>(x: T) -> U;
/// Truncates an integer vector to a bitmask.
///
@ -597,7 +598,7 @@ pub unsafe fn simd_reduce_xor<T, U>(x: T) -> U;
/// `x` must contain only `0` and `!0`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_bitmask<T, U>(x: T) -> U;
pub const unsafe fn simd_bitmask<T, U>(x: T) -> U;
/// Selects elements from a mask.
///
@ -613,7 +614,7 @@ pub unsafe fn simd_bitmask<T, U>(x: T) -> U;
/// `mask` must only contain `0` and `!0`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_select<M, T>(mask: M, if_true: T, if_false: T) -> T;
pub const unsafe fn simd_select<M, T>(mask: M, if_true: T, if_false: T) -> T;
/// Selects elements from a bitmask.
///
@ -629,7 +630,7 @@ pub unsafe fn simd_select<M, T>(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, T>(m: M, yes: T, no: T) -> T;
pub const unsafe fn simd_select_bitmask<M, T>(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, T>(m: M, yes: T, no: T) -> T;
/// Operates as if by `<ptr>::wrapping_offset`.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_arith_offset<T, U>(ptr: T, offset: U) -> T;
pub const unsafe fn simd_arith_offset<T, U>(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<T, U>(ptr: T) -> U;
pub const unsafe fn simd_cast_ptr<T, U>(ptr: T) -> U;
/// Exposes a vector of pointers as a vector of addresses.
///
@ -666,56 +667,56 @@ pub unsafe fn simd_expose_provenance<T, U>(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<T, U>(addr: T) -> U;
pub const unsafe fn simd_with_exposed_provenance<T, U>(addr: T) -> U;
/// Swaps bytes of each element.
///
/// `T` must be a vector of integers.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_bswap<T>(x: T) -> T;
pub const unsafe fn simd_bswap<T>(x: T) -> T;
/// Reverses bits of each element.
///
/// `T` must be a vector of integers.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_bitreverse<T>(x: T) -> T;
pub const unsafe fn simd_bitreverse<T>(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<T>(x: T) -> T;
pub const unsafe fn simd_ctlz<T>(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<T>(x: T) -> T;
pub const unsafe fn simd_ctpop<T>(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<T>(x: T) -> T;
pub const unsafe fn simd_cttz<T>(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<T>(x: T) -> T;
pub const unsafe fn simd_ceil<T>(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<T>(x: T) -> T;
pub const unsafe fn simd_floor<T>(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<T>(x: T) -> T;
/// `T` must be a vector of floats.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_round<T>(x: T) -> T;
pub const unsafe fn simd_round<T>(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<T>(x: T) -> T;
/// `T` must be a vector of floats.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_round_ties_even<T>(x: T) -> T;
pub const unsafe fn simd_round_ties_even<T>(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<T>(x: T) -> T;
/// `T` must be a vector of floats.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_trunc<T>(x: T) -> T;
pub const unsafe fn simd_trunc<T>(x: T) -> T;
/// Takes the square root of each element.
///
@ -753,7 +754,7 @@ pub unsafe fn simd_fsqrt<T>(x: T) -> T;
/// `T` must be a vector of floats.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_fma<T>(x: T, y: T, z: T) -> T;
pub const unsafe fn simd_fma<T>(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<T>(x: T, y: T, z: T) -> T;
/// `T` must be a vector of floats.
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_relaxed_fma<T>(x: T, y: T, z: T) -> T;
pub const unsafe fn simd_relaxed_fma<T>(x: T, y: T, z: T) -> T;
// Computes the sine of each element.
///

View file

@ -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)]

View file

@ -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<u32> {
// 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.

View file

@ -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])?;

View file

@ -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('"')
}
}

View file

@ -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);
}

View file

@ -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()));
}

View file

@ -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"]

View file

@ -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()
}
}

View file

@ -303,3 +303,9 @@ fn clone_to_uninit() {
unsafe { a.clone_to_uninit(ptr::from_mut::<OsStr>(&mut b).cast()) };
assert_eq!(a, &*b);
}
#[test]
fn debug() {
let s = "'single quotes'";
assert_eq!(format!("{:?}", OsStr::new(s)), format!("{:?}", s));
}

View file

@ -5,27 +5,10 @@ pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::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 {

View file

@ -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 <OsStr as Debug>::fmt matches <str as Debug>::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

View file

@ -8,30 +8,6 @@ pub struct Env {
iter: EnvIterator,
}
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::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;

View file

@ -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"]

View file

@ -846,6 +846,10 @@ impl Build {
features.insert("compiler-builtins-mem");
}
if self.config.llvm_enzyme {
features.insert("llvm_enzyme");
}
features.into_iter().collect::<Vec<_>>().join(" ")
}

View file

@ -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=<options>` compiler flag to adjust the behaviour of the autodiff feature.
Multiple options can be separated with a comma. Valid options are:
Multiple options can be separated with a comma.
`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
## Syntax
```bash
rustc -Z autodiff=Enable[,options]
```
Where `options` can be:
- `Enable` - Required flag to enable autodiff
- `PrintTA` - print Type Analysis Information
- `PrintTAFn=<fn_name>` - 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
```

View file

@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
#[rustc_intrinsic]
#[rustc_nounwind]
pub unsafe fn simd_shuffle_const_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
pub const unsafe fn simd_shuffle_const_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
fn simd_ops_f16() {
use intrinsics::*;

View file

@ -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<T: Copy, const N: usize> Clone for Simd<T, N> {
}
}
impl<T: PartialEq, const N: usize> PartialEq for Simd<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for Simd<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
}
}
impl<T, const N: usize> core::ops::Index<usize> for Simd<T, N> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.as_array()[i]
}
}
impl<T, const N: usize> Simd<T, N> {
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<u8, 2>;
@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
pub type i128x2 = Simd<i128, 2>;
pub type i128x4 = Simd<i128, 4>;
pub type usizex2 = Simd<usize, 2>;
pub type usizex4 = Simd<usize, 4>;
pub type usizex8 = Simd<usize, 8>;
pub type isizex2 = Simd<isize, 2>;
pub type isizex4 = Simd<isize, 4>;
pub type isizex8 = Simd<isize, 8>;
pub type f32x2 = Simd<f32, 2>;
pub type f32x4 = Simd<f32, 4>;
pub type f32x8 = Simd<f32, 8>;
@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
// 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<T, const N: usize>(pub [T; N]);
impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
}
}
impl<T: PartialEq, const N: usize> PartialEq for PackedSimd<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for PackedSimd<T, N> {
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<T, const N: usize> PackedSimd<T, N> {
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<T: $([$const_])? PartialEq, const N: usize> $($const_)? PartialEq for Simd<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T, const N: usize> $($const_)? core::ops::Index<usize> for Simd<T, N> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.as_array()[i]
}
}
impl<T: $([$const_])? PartialEq, const N: usize> $($const_)? PartialEq for PackedSimd<T, N>
{
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 <https://github.com/rust-lang/rust/issues/119826> 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;

View file

@ -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<String, String>,
//~^ NOTE `String` does not implement `BuildHasher`
//~| ERROR binary operation
//~| HELP use a HashMap
}
fn main() {
let h1 = HashSet::<usize, usize>::with_hasher(0);
h1.insert(1);
//~^ ERROR its trait bounds were not satisfied
//~| NOTE the following trait bounds
//~| HELP use a HashMap
}

View file

@ -0,0 +1,29 @@
error[E0369]: binary operation `==` cannot be applied to type `HashSet<String, String>`
--> $DIR/hashset_generics.rs:8:5
|
LL | #[derive(PartialEq)]
| --------- in this derive macro expansion
...
LL | pub parameters: HashSet<String, String>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
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<usize, usize>`, 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`.

View file

@ -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]) {}
}

View file

@ -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 <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
= 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 <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
= note: this warning originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 2 warnings emitted

View file

@ -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,37 +47,7 @@ fn main() {
unsafe {
let r = simd_fabs(y);
assert_approx_eq!(x, r);
let r = simd_fcos(z);
assert_approx_eq!(x, r);
let r = simd_fexp(z);
assert_approx_eq!(x, r);
let r = simd_fexp2(z);
assert_approx_eq!(x, r);
let r = simd_fma(x, h, h);
assert_approx_eq!(x, r);
let r = simd_relaxed_fma(x, h, h);
assert_approx_eq!(x, r);
let r = simd_fsqrt(x);
assert_approx_eq!(x, r);
let r = simd_flog(x);
assert_approx_eq!(z, r);
let r = simd_flog2(x);
assert_approx_eq!(z, r);
let r = simd_flog10(x);
assert_approx_eq!(z, r);
let r = simd_fsin(z);
assert_approx_eq!(z, r);
assert_eq!(x, r);
// rounding functions
let r = simd_floor(h);
@ -90,5 +64,48 @@ fn main() {
let r = simd_trunc(h);
assert_eq!(z, r);
let r = simd_fma(x, h, h);
assert_approx_eq!(x, r);
let r = simd_relaxed_fma(x, h, h);
assert_approx_eq!(x, r);
}
}
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_fexp(z);
assert_approx_eq!(x, r);
let r = simd_fexp2(z);
assert_approx_eq!(x, r);
let r = simd_fsqrt(x);
assert_approx_eq!(x, r);
let r = simd_flog(x);
assert_approx_eq!(z, r);
let r = simd_flog2(x);
assert_approx_eq!(z, r);
let r = simd_flog10(x);
assert_approx_eq!(z, r);
let r = simd_fsin(z);
assert_approx_eq!(z, r);
}
}
fn main() {
const { simple_math() };
simple_math();
special_math();
}

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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<const N: usize> = Simd<i32, N>;
fn main() {
const fn saturating() {
// unsigned
{
const M: u32 = u32::MAX;
@ -84,3 +85,8 @@ fn main() {
}
}
}
fn main() {
const { saturating() };
saturating();
}

View file

@ -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<T> = Simd<T, 2>;
fn main() {
const fn as_simd() {
unsafe {
let u: V::<u32> = Simd([u32::MIN, u32::MAX]);
let i: V<i16> = simd_as(u);
@ -47,3 +48,8 @@ fn main() {
assert_eq!(u[1], f[1] as usize);
}
}
fn main() {
const { as_simd() };
as_simd();
}

View file

@ -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)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
use minisimd::*;
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]);
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct Tx4<T>(pub [T; 4]);
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<usize> = 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();
}

View file

@ -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();
}

View file

@ -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<T> = Simd<T, 2>;
fn main() {
const fn cast() {
unsafe {
let u: V::<u32> = Simd([i16::MIN as u32, i16::MAX as u32]);
let i: V<i16> = simd_cast(u);
@ -56,3 +57,8 @@ fn main() {
assert_eq!(u[1], f[1] as usize);
}
}
fn main() {
const { cast() };
cast();
}

View file

@ -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<T> = Simd<T, 4>;
fn main() {
const fn cast_ptr_width() {
let u: V::<usize> = Simd([0, 1, 2, 3]);
let uu32: V<u32> = unsafe { simd_cast(u) };
let ui64: V<i64> = 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::<u32>::from_array([0, 1, 2, 3]));
assert_eq!(ui64, V::<i64>::from_array([0, 1, 2, 3]));
}
fn main() {
const { cast_ptr_width() };
cast_ptr_width();
}

View file

@ -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();
}

View file

@ -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,11 +21,59 @@ 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_dyn(x2, 0, 100), i32x2::from_array([100, 21]));
all_eq!(simd_insert_dyn(x2, 1, 100), i32x2::from_array([20, 100]));
all_eq!(simd_insert_dyn(x4, 0, 100), i32x4::from_array([100, 41, 42, 43]));
all_eq!(simd_insert_dyn(x4, 1, 100), i32x4::from_array([40, 100, 42, 43]));
all_eq!(simd_insert_dyn(x4, 2, 100), i32x4::from_array([40, 41, 100, 43]));
all_eq!(simd_insert_dyn(x4, 3, 100), i32x4::from_array([40, 41, 42, 100]));
all_eq!(simd_insert_dyn(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87]));
all_eq!(simd_insert_dyn(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87]));
all_eq!(simd_insert_dyn(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100]));
all_eq!(simd_extract_dyn(x2, 0), 20);
all_eq!(simd_extract_dyn(x2, 1), 21);
all_eq!(simd_extract_dyn(x4, 0), 40);
all_eq!(simd_extract_dyn(x4, 1), 41);
all_eq!(simd_extract_dyn(x4, 2), 42);
all_eq!(simd_extract_dyn(x4, 3), 43);
all_eq!(simd_extract_dyn(x8, 0), 80);
all_eq!(simd_extract_dyn(x8, 1), 81);
all_eq!(simd_extract_dyn(x8, 2), 82);
all_eq!(simd_extract_dyn(x8, 3), 83);
all_eq!(simd_extract_dyn(x8, 4), 84);
all_eq!(simd_extract_dyn(x8, 5), 85);
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]);
@ -63,83 +112,36 @@ fn main() {
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]));
all_eq!(simd_insert_dyn(x4, 0, 100), i32x4::from_array([100, 41, 42, 43]));
all_eq!(simd_insert_dyn(x4, 1, 100), i32x4::from_array([40, 100, 42, 43]));
all_eq!(simd_insert_dyn(x4, 2, 100), i32x4::from_array([40, 41, 100, 43]));
all_eq!(simd_insert_dyn(x4, 3, 100), i32x4::from_array([40, 41, 42, 100]));
all_eq!(simd_insert_dyn(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87]));
all_eq!(simd_insert_dyn(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87]));
all_eq!(simd_insert_dyn(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87]));
all_eq!(simd_insert_dyn(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100]));
all_eq!(simd_extract_dyn(x2, 0), 20);
all_eq!(simd_extract_dyn(x2, 1), 21);
all_eq!(simd_extract_dyn(x4, 0), 40);
all_eq!(simd_extract_dyn(x4, 1), 41);
all_eq!(simd_extract_dyn(x4, 2), 42);
all_eq!(simd_extract_dyn(x4, 3), 43);
all_eq!(simd_extract_dyn(x8, 0), 80);
all_eq!(simd_extract_dyn(x8, 1), 81);
all_eq!(simd_extract_dyn(x8, 2), 82);
all_eq!(simd_extract_dyn(x8, 3), 83);
all_eq!(simd_extract_dyn(x8, 4), 84);
all_eq!(simd_extract_dyn(x8, 5), 85);
all_eq!(simd_extract_dyn(x8, 6), 86);
all_eq!(simd_extract_dyn(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();
}

View file

@ -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<T> = Simd<T, 4>;
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();
}

View file

@ -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)]
#[path = "../../../auxiliary/minisimd.rs"]
mod minisimd;
use minisimd::*;
use std::intrinsics::simd::*;
#[repr(simd)]
#[derive(Copy, Clone)]
struct i32x4(pub [i32; 4]);
#[repr(simd)]
#[derive(Copy, Clone)]
struct u32x4(pub [u32; 4]);
#[repr(simd)]
#[derive(Copy, Clone)]
struct f32x4(pub [f32; 4]);
#[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();
}

View file

@ -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();
}

View file

@ -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::<u8, 4>([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();
}

View file

@ -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<i32, 10>;
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<i32, 20>;
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();
}

View file

@ -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::<i8, 4>([-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();
}