1use either::Either;
2use rustc_abi::{BackendRepr, Endian};
3use rustc_apfloat::ieee::{Double, Half, Quad, Single};
4use rustc_apfloat::{Float, Round};
5use rustc_middle::mir::interpret::{InterpErrorKind, Pointer, UndefinedBehaviorInfo};
6use rustc_middle::ty::{FloatTy, SimdAlign};
7use rustc_middle::{err_ub_format, mir, throw_unsup_format, ty};
8use rustc_span::{Symbol, bug, span_bug, sym};
9use tracing::trace;
10
11use super::{
12 ImmTy, InterpCx, InterpResult, Machine, MinMax, MulAddType, OpTy, PlaceTy, Provenance, Scalar,
13 Size, TyAndLayout, interp_ok, throw_ub_format,
14};
15use crate::interpret::Writeable;
16
17impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
18 pub fn eval_simd_intrinsic(
22 &mut self,
23 intrinsic_name: Symbol,
24 generic_args: ty::GenericArgs<'tcx>,
25 args: &[OpTy<'tcx, M::Provenance>],
26 dest: &PlaceTy<'tcx, M::Provenance>,
27 ret: Option<mir::BasicBlock>,
28 ) -> InterpResult<'tcx, bool> {
29 let dest = dest.force_mplace(self)?;
30
31 match intrinsic_name {
32 sym::simd_insert | sym::simd_insert_dyn => {
33 let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
34 let elem = &args[2];
35 let (input, input_len) = self.project_to_simd(&args[0])?;
36 let (dest, dest_len) = self.project_to_simd(&dest)?;
37 {
match (&input_len, &dest_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("Return vector length must match input length")));
}
}
}
};assert_eq!(input_len, dest_len, "Return vector length must match input length");
38 if index >= input_len {
40 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` index {1} is out-of-bounds of vector with length {2}",
intrinsic_name, index, input_len))
})));throw_ub_format!(
41 "`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}"
42 );
43 }
44
45 for i in 0..dest_len {
46 let place = self.project_index(&dest, i)?;
47 let value =
48 if i == index { elem.clone() } else { self.project_index(&input, i)? };
49 self.copy_op(&value, &place)?;
50 }
51 }
52 sym::simd_extract | sym::simd_extract_dyn => {
53 let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
54 let (input, input_len) = self.project_to_simd(&args[0])?;
55 if index >= input_len {
57 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` index {1} is out-of-bounds of vector with length {2}",
intrinsic_name, index, input_len))
})));throw_ub_format!(
58 "`{intrinsic_name}` index {index} is out-of-bounds of vector with length {input_len}"
59 );
60 }
61 self.copy_op(&self.project_index(&input, index)?, &dest)?;
62 }
63 sym::simd_splat => {
64 let elem = &args[0];
65 let (dest, dest_len) = self.project_to_simd(&dest)?;
66
67 for i in 0..dest_len {
68 let place = self.project_index(&dest, i)?;
69 self.copy_op(elem, &place)?;
70 }
71 }
72 sym::simd_neg
73 | sym::simd_fabs
74 | sym::simd_ceil
75 | sym::simd_floor
76 | sym::simd_round
77 | sym::simd_round_ties_even
78 | sym::simd_trunc
79 | sym::simd_ctlz
80 | sym::simd_ctpop
81 | sym::simd_cttz
82 | sym::simd_bswap
83 | sym::simd_bitreverse => {
84 let (op, op_len) = self.project_to_simd(&args[0])?;
85 let (dest, dest_len) = self.project_to_simd(&dest)?;
86
87 {
match (&dest_len, &op_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, op_len);
88
89 #[derive(#[automatically_derived]impl ::core::marker::Copy for Op { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for Op {
}
#[automatically_derived]impl ::core::clone::Clone for Op {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<mir::UnOp>;
let _: ::core::clone::AssertParamIsClone<rustc_apfloat::Round>;
let _: ::core::clone::AssertParamIsClone<Symbol>;
*self
}
}Clone)]
90 enum Op {
91 MirOp(mir::UnOp),
92 Abs,
93 Round(rustc_apfloat::Round),
94 Numeric(Symbol),
95 }
96 let which = match intrinsic_name {
97 sym::simd_neg => Op::MirOp(mir::UnOp::Neg),
98 sym::simd_fabs => Op::Abs,
99 sym::simd_ceil => Op::Round(rustc_apfloat::Round::TowardPositive),
100 sym::simd_floor => Op::Round(rustc_apfloat::Round::TowardNegative),
101 sym::simd_round => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
102 sym::simd_round_ties_even => Op::Round(rustc_apfloat::Round::NearestTiesToEven),
103 sym::simd_trunc => Op::Round(rustc_apfloat::Round::TowardZero),
104 sym::simd_ctlz => Op::Numeric(sym::ctlz),
105 sym::simd_ctpop => Op::Numeric(sym::ctpop),
106 sym::simd_cttz => Op::Numeric(sym::cttz),
107 sym::simd_bswap => Op::Numeric(sym::bswap),
108 sym::simd_bitreverse => Op::Numeric(sym::bitreverse),
109 _ => ::core::panicking::unreachable_default_msg()unreachable!(),
110 };
111
112 for i in 0..dest_len {
113 let op = self.read_immediate(&self.project_index(&op, i)?)?;
114 let dest = self.project_index(&dest, i)?;
115 let val = match which {
116 Op::MirOp(mir_op) => {
117 self.unary_op(mir_op, &op)?.to_scalar()
119 }
120 Op::Abs => {
121 let ty::Float(float_ty) = op.layout.ty.kind() else {
123 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("{0} operand is not a float", intrinsic_name),
Location::caller())span_bug!(
124 self.cur_span(),
125 "{} operand is not a float",
126 intrinsic_name
127 )
128 };
129 let op = op.to_scalar();
130 match float_ty {
132 FloatTy::F16 => Scalar::from_f16(op.to_f16()?.abs()),
133 FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()),
134 FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()),
135 FloatTy::F128 => Scalar::from_f128(op.to_f128()?.abs()),
136 }
137 }
138 Op::Round(rounding) => {
139 let ty::Float(float_ty) = op.layout.ty.kind() else {
140 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("{0} operand is not a float", intrinsic_name),
Location::caller())span_bug!(
141 self.cur_span(),
142 "{} operand is not a float",
143 intrinsic_name
144 )
145 };
146 let op = op.to_scalar();
147 match float_ty {
148 FloatTy::F16 => {
149 self.float_round::<Half>(op.to_float()?, rounding)?
150 }
151 FloatTy::F32 => {
152 self.float_round::<Single>(op.to_float()?, rounding)?
153 }
154 FloatTy::F64 => {
155 self.float_round::<Double>(op.to_float()?, rounding)?
156 }
157 FloatTy::F128 => {
158 self.float_round::<Quad>(op.to_float()?, rounding)?
159 }
160 }
161 }
162 Op::Numeric(name) => {
163 self.numeric_intrinsic(name, op.to_scalar(), op.layout, op.layout)?
164 }
165 };
166 self.write_scalar(val, &dest)?;
167 }
168 }
169 sym::simd_add
170 | sym::simd_sub
171 | sym::simd_mul
172 | sym::simd_div
173 | sym::simd_rem
174 | sym::simd_shl
175 | sym::simd_shr
176 | sym::simd_and
177 | sym::simd_or
178 | sym::simd_xor
179 | sym::simd_eq
180 | sym::simd_ne
181 | sym::simd_lt
182 | sym::simd_le
183 | sym::simd_gt
184 | sym::simd_ge
185 | sym::simd_maximum_number_nsz
186 | sym::simd_minimum_number_nsz
187 | sym::simd_saturating_add
188 | sym::simd_saturating_sub
189 | sym::simd_arith_offset => {
190 use mir::BinOp;
191
192 let (left, left_len) = self.project_to_simd(&args[0])?;
193 let (right, right_len) = self.project_to_simd(&args[1])?;
194 let (dest, dest_len) = self.project_to_simd(&dest)?;
195
196 {
match (&dest_len, &left_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, left_len);
197 {
match (&dest_len, &right_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, right_len);
198
199 enum Op {
200 MirOp(BinOp),
201 SaturatingOp(BinOp),
202 FMinMax(MinMax),
203 WrappingOffset,
204 }
205 let which = match intrinsic_name {
206 sym::simd_add => Op::MirOp(BinOp::Add),
207 sym::simd_sub => Op::MirOp(BinOp::Sub),
208 sym::simd_mul => Op::MirOp(BinOp::Mul),
209 sym::simd_div => Op::MirOp(BinOp::Div),
210 sym::simd_rem => Op::MirOp(BinOp::Rem),
211 sym::simd_shl => Op::MirOp(BinOp::ShlUnchecked),
212 sym::simd_shr => Op::MirOp(BinOp::ShrUnchecked),
213 sym::simd_and => Op::MirOp(BinOp::BitAnd),
214 sym::simd_or => Op::MirOp(BinOp::BitOr),
215 sym::simd_xor => Op::MirOp(BinOp::BitXor),
216 sym::simd_eq => Op::MirOp(BinOp::Eq),
217 sym::simd_ne => Op::MirOp(BinOp::Ne),
218 sym::simd_lt => Op::MirOp(BinOp::Lt),
219 sym::simd_le => Op::MirOp(BinOp::Le),
220 sym::simd_gt => Op::MirOp(BinOp::Gt),
221 sym::simd_ge => Op::MirOp(BinOp::Ge),
222 sym::simd_maximum_number_nsz => Op::FMinMax(MinMax::MaximumNumberNsz),
223 sym::simd_minimum_number_nsz => Op::FMinMax(MinMax::MinimumNumberNsz),
224 sym::simd_saturating_add => Op::SaturatingOp(BinOp::Add),
225 sym::simd_saturating_sub => Op::SaturatingOp(BinOp::Sub),
226 sym::simd_arith_offset => Op::WrappingOffset,
227 _ => ::core::panicking::unreachable_default_msg()unreachable!(),
228 };
229
230 for i in 0..dest_len {
231 let left = self.read_immediate(&self.project_index(&left, i)?)?;
232 let right = self.read_immediate(&self.project_index(&right, i)?)?;
233 let dest = self.project_index(&dest, i)?;
234 let val = match which {
235 Op::MirOp(mir_op) => {
236 let val = self.binary_op(mir_op, &left, &right).map_err_kind(|kind| {
238 match kind {
239 InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ShiftOverflow { shift_amount, .. }) => {
240 let shift_amount = match shift_amount {
242 Either::Left(v) => v.to_string(),
243 Either::Right(v) => v.to_string(),
244 };
245 ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("overflowing shift by {0} in `{1}` in lane {2}",
shift_amount, intrinsic_name, i))
})))err_ub_format!("overflowing shift by {shift_amount} in `{intrinsic_name}` in lane {i}")
246 }
247 kind => kind
248 }
249 })?;
250 if #[allow(non_exhaustive_omitted_patterns)] match mir_op {
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge =>
true,
_ => false,
}matches!(
251 mir_op,
252 BinOp::Eq
253 | BinOp::Ne
254 | BinOp::Lt
255 | BinOp::Le
256 | BinOp::Gt
257 | BinOp::Ge
258 ) {
259 {
match (&val.layout.ty, &self.tcx.types.bool) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(val.layout.ty, self.tcx.types.bool);
261 let val = val.to_scalar().to_bool().unwrap();
262 bool_to_simd_element(val, dest.layout.size)
263 } else {
264 {
match (&val.layout.ty, &self.tcx.types.bool) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_ne!(val.layout.ty, self.tcx.types.bool);
265 {
match (&val.layout.ty, &dest.layout.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(val.layout.ty, dest.layout.ty);
266 val.to_scalar()
267 }
268 }
269 Op::SaturatingOp(mir_op) => self.saturating_arith(mir_op, &left, &right)?,
270 Op::WrappingOffset => {
271 let ptr = left.to_scalar().to_pointer(self);
272 let offset_count = right.to_scalar().to_target_isize(self)?;
273 let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
274
275 let pointee_size =
276 i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
277 let offset_bytes = offset_count.wrapping_mul(pointee_size);
278 let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, self);
279 Scalar::from_maybe_pointer(offset_ptr, self)
280 }
281 Op::FMinMax(op) => self.fminmax_op(op, &left, &right)?,
282 };
283 self.write_scalar(val, &dest)?;
284 }
285 }
286 sym::simd_reduce_and
287 | sym::simd_reduce_or
288 | sym::simd_reduce_xor
289 | sym::simd_reduce_any
290 | sym::simd_reduce_all
291 | sym::simd_reduce_max
292 | sym::simd_reduce_min => {
293 use mir::BinOp;
294
295 let (op, op_len) = self.project_to_simd(&args[0])?;
296
297 let imm_from_bool = |b| {
298 ImmTy::from_scalar(
299 Scalar::from_bool(b),
300 self.layout_of(self.tcx.types.bool).unwrap(),
301 )
302 };
303
304 enum Op {
305 MirOp(BinOp),
306 MirOpBool(BinOp),
307 MinMax(MinMax),
308 }
309 let which = match intrinsic_name {
310 sym::simd_reduce_and => Op::MirOp(BinOp::BitAnd),
311 sym::simd_reduce_or => Op::MirOp(BinOp::BitOr),
312 sym::simd_reduce_xor => Op::MirOp(BinOp::BitXor),
313 sym::simd_reduce_any => Op::MirOpBool(BinOp::BitOr),
314 sym::simd_reduce_all => Op::MirOpBool(BinOp::BitAnd),
315 sym::simd_reduce_max => Op::MinMax(MinMax::MaximumNumberNsz),
316 sym::simd_reduce_min => Op::MinMax(MinMax::MinimumNumberNsz),
317 _ => ::core::panicking::unreachable_default_msg()unreachable!(),
318 };
319
320 let mut res = self.read_immediate(&self.project_index(&op, 0)?)?;
322 if #[allow(non_exhaustive_omitted_patterns)] match which {
Op::MirOpBool(_) => true,
_ => false,
}matches!(which, Op::MirOpBool(_)) {
323 res = imm_from_bool(simd_element_to_bool(res)?);
325 }
326 for i in 1..op_len {
327 let op = self.read_immediate(&self.project_index(&op, i)?)?;
328 res = match which {
329 Op::MirOp(mir_op) => self.binary_op(mir_op, &res, &op)?,
330 Op::MirOpBool(mir_op) => {
331 let op = imm_from_bool(simd_element_to_bool(op)?);
332 self.binary_op(mir_op, &res, &op)?
333 }
334 Op::MinMax(mmop) => {
335 if #[allow(non_exhaustive_omitted_patterns)] match res.layout.ty.kind() {
ty::Float(_) => true,
_ => false,
}matches!(res.layout.ty.kind(), ty::Float(_)) {
336 ImmTy::from_scalar(self.fminmax_op(mmop, &res, &op)?, res.layout)
337 } else {
338 let mirop = match mmop {
340 MinMax::MinimumNumberNsz | MinMax::Minimum => BinOp::Le,
341 MinMax::MaximumNumberNsz | MinMax::Maximum => BinOp::Ge,
342 };
343 if self.binary_op(mirop, &res, &op)?.to_scalar().to_bool()? {
344 res
345 } else {
346 op
347 }
348 }
349 }
350 };
351 }
352 self.write_immediate(*res, &dest)?;
353 }
354 sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => {
355 use mir::BinOp;
356
357 let (op, op_len) = self.project_to_simd(&args[0])?;
358 let init = self.read_immediate(&args[1])?;
359
360 let mir_op = match intrinsic_name {
361 sym::simd_reduce_add_ordered => BinOp::Add,
362 sym::simd_reduce_mul_ordered => BinOp::Mul,
363 _ => ::core::panicking::unreachable_default_msg()unreachable!(),
364 };
365
366 let mut res = init;
367 for i in 0..op_len {
368 let op = self.read_immediate(&self.project_index(&op, i)?)?;
369 res = self.binary_op(mir_op, &res, &op)?;
370 }
371 self.write_immediate(*res, &dest)?;
372 }
373 sym::simd_select => {
374 let (mask, mask_len) = self.project_to_simd(&args[0])?;
375 let (yes, yes_len) = self.project_to_simd(&args[1])?;
376 let (no, no_len) = self.project_to_simd(&args[2])?;
377 let (dest, dest_len) = self.project_to_simd(&dest)?;
378
379 {
match (&dest_len, &mask_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, mask_len);
380 {
match (&dest_len, &yes_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, yes_len);
381 {
match (&dest_len, &no_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, no_len);
382
383 for i in 0..dest_len {
384 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
385 let yes = self.read_immediate(&self.project_index(&yes, i)?)?;
386 let no = self.read_immediate(&self.project_index(&no, i)?)?;
387 let dest = self.project_index(&dest, i)?;
388
389 let val = if simd_element_to_bool(mask)? { yes } else { no };
390 self.write_immediate(*val, &dest)?;
391 }
392 }
393 sym::simd_select_bitmask => {
395 let mask = &args[0];
396 let (yes, yes_len) = self.project_to_simd(&args[1])?;
397 let (no, no_len) = self.project_to_simd(&args[2])?;
398 let (dest, dest_len) = self.project_to_simd(&dest)?;
399 let bitmask_len = dest_len.next_multiple_of(8);
400 if bitmask_len > 64 {
401 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::Unsupported(::rustc_middle::mir::interpret::UnsupportedOpInfo::Unsupported(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("simd_select_bitmask: vectors larger than 64 elements are currently not supported"))
})));throw_unsup_format!(
402 "simd_select_bitmask: vectors larger than 64 elements are currently not supported"
403 );
404 }
405
406 {
match (&dest_len, &yes_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, yes_len);
407 {
match (&dest_len, &no_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, no_len);
408
409 let mask: u64 = match mask.layout.ty.kind() {
411 ty::Uint(_) => {
412 if !(mask.layout.size.bits() >= bitmask_len) {
::core::panicking::panic("assertion failed: mask.layout.size.bits() >= bitmask_len")
};assert!(mask.layout.size.bits() >= bitmask_len);
414 self.read_scalar(mask)?.to_bits(mask.layout.size)?.try_into().unwrap()
415 }
416 ty::Array(elem, _len) if elem == &self.tcx.types.u8 => {
417 {
match (&mask.layout.size.bits(), &bitmask_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(mask.layout.size.bits(), bitmask_len);
419 let mask = mask.assert_mem_place(); let mask_bytes =
422 self.read_bytes_ptr_strip_provenance(mask.ptr(), mask.layout.size)?;
423 let mask_size = mask.layout.size.bytes_usize();
425 let mut mask_arr = [0u8; 8];
426 match self.tcx.data_layout.endian {
427 Endian::Little => {
428 mask_arr[..mask_size].copy_from_slice(mask_bytes);
430 u64::from_le_bytes(mask_arr)
431 }
432 Endian::Big => {
433 let i = mask_arr.len().strict_sub(mask_size);
435 mask_arr[i..].copy_from_slice(mask_bytes);
436 u64::from_be_bytes(mask_arr)
437 }
438 }
439 }
440 _ => ::rustc_span::macros::bug_impl(None,
format_args!("simd_select_bitmask: invalid mask type {0}",
mask.layout.ty), Location::caller())bug!("simd_select_bitmask: invalid mask type {}", mask.layout.ty),
441 };
442
443 let dest_len = u32::try_from(dest_len).unwrap();
444 for i in 0..dest_len {
445 let bit_i = simd_bitmask_index(i, dest_len, self.tcx.data_layout.endian);
446 let mask = mask & 1u64.strict_shl(bit_i);
447 let yes = self.read_immediate(&self.project_index(&yes, i.into())?)?;
448 let no = self.read_immediate(&self.project_index(&no, i.into())?)?;
449 let dest = self.project_index(&dest, i.into())?;
450
451 let val = if mask != 0 { yes } else { no };
452 self.write_immediate(*val, &dest)?;
453 }
454 }
456 sym::simd_bitmask => {
458 let (op, op_len) = self.project_to_simd(&args[0])?;
459 let bitmask_len = op_len.next_multiple_of(8);
460 if bitmask_len > 64 {
461 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::Unsupported(::rustc_middle::mir::interpret::UnsupportedOpInfo::Unsupported(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("simd_bitmask: vectors larger than 64 elements are currently not supported"))
})));throw_unsup_format!(
462 "simd_bitmask: vectors larger than 64 elements are currently not supported"
463 );
464 }
465
466 let op_len = u32::try_from(op_len).unwrap();
467 let mut res = 0u64;
468 for i in 0..op_len {
469 let op = self.read_immediate(&self.project_index(&op, i.into())?)?;
470 if simd_element_to_bool(op)? {
471 let bit_i = simd_bitmask_index(i, op_len, self.tcx.data_layout.endian);
472 res |= 1u64.strict_shl(bit_i);
473 }
474 }
475 match dest.layout.ty.kind() {
478 ty::Uint(_) => {
479 if !(dest.layout.size.bits() >= bitmask_len) {
::core::panicking::panic("assertion failed: dest.layout.size.bits() >= bitmask_len")
};assert!(dest.layout.size.bits() >= bitmask_len);
481 self.write_scalar(Scalar::from_uint(res, dest.layout.size), &dest)?;
482 }
483 ty::Array(elem, _len) if elem == &self.tcx.types.u8 => {
484 {
match (&dest.layout.size.bits(), &bitmask_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest.layout.size.bits(), bitmask_len);
486 let res_size = dest.layout.size.bytes_usize();
488 let res_bytes;
489 let res_bytes_slice = match self.tcx.data_layout.endian {
490 Endian::Little => {
491 res_bytes = res.to_le_bytes();
492 &res_bytes[..res_size] }
494 Endian::Big => {
495 res_bytes = res.to_be_bytes();
496 &res_bytes[res_bytes.len().strict_sub(res_size)..] }
498 };
499 self.write_bytes_ptr(dest.ptr(), res_bytes_slice.iter().cloned())?;
500 }
501 _ => ::rustc_span::macros::bug_impl(None,
format_args!("simd_bitmask: invalid return type {0}", dest.layout.ty),
Location::caller())bug!("simd_bitmask: invalid return type {}", dest.layout.ty),
502 }
503 }
504 sym::simd_cast
505 | sym::simd_as
506 | sym::simd_cast_ptr
507 | sym::simd_with_exposed_provenance => {
508 let (op, op_len) = self.project_to_simd(&args[0])?;
509 let (dest, dest_len) = self.project_to_simd(&dest)?;
510
511 {
match (&dest_len, &op_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, op_len);
512
513 let unsafe_cast = intrinsic_name == sym::simd_cast;
514 let safe_cast = intrinsic_name == sym::simd_as;
515 let ptr_cast = intrinsic_name == sym::simd_cast_ptr;
516 let from_exposed_cast = intrinsic_name == sym::simd_with_exposed_provenance;
517
518 for i in 0..dest_len {
519 let op = self.read_immediate(&self.project_index(&op, i)?)?;
520 let dest = self.project_index(&dest, i)?;
521
522 let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
523 (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_))
525 if safe_cast || unsafe_cast =>
526 self.int_to_int_or_float(&op, dest.layout)?,
527 (ty::Float(_), ty::Float(_)) if safe_cast || unsafe_cast =>
529 self.float_to_float_or_int(&op, dest.layout)?,
530 (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
532 self.float_to_float_or_int(&op, dest.layout)?,
533 (ty::Float(_), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
535 self.float_to_int_checked(&op, dest.layout, Round::TowardZero)?
536 .ok_or_else(|| {
537 ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`simd_cast` intrinsic called on {1} which cannot be represented in target type `{0:?}`",
dest.layout.ty, op))
})))err_ub_format!(
538 "`simd_cast` intrinsic called on {op} which cannot be represented in target type `{:?}`",
539 dest.layout.ty
540 )
541 })?
542 }
543 (ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast =>
545 self.ptr_to_ptr(&op, dest.layout)?,
546 (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
548 self.pointer_with_exposed_provenance_cast(&op, dest.layout)?,
549 _ =>
551 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::Unsupported(::rustc_middle::mir::interpret::UnsupportedOpInfo::Unsupported(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Unsupported SIMD cast from element type {0} to {1}",
op.layout.ty, dest.layout.ty))
})))throw_unsup_format!(
552 "Unsupported SIMD cast from element type {from_ty} to {to_ty}",
553 from_ty = op.layout.ty,
554 to_ty = dest.layout.ty,
555 ),
556 };
557 self.write_immediate(*val, &dest)?;
558 }
559 }
560 sym::simd_shuffle_const_generic => {
561 let (left, left_len) = self.project_to_simd(&args[0])?;
562 let (right, right_len) = self.project_to_simd(&args[1])?;
563 let (dest, dest_len) = self.project_to_simd(&dest)?;
564
565 let index = generic_args[2].expect_const().to_branch();
566 let index_len = index.len();
567
568 {
match (&left_len, &right_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(left_len, right_len);
569 {
match (&u64::try_from(index_len).unwrap(), &dest_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(u64::try_from(index_len).unwrap(), dest_len);
570
571 for i in 0..dest_len {
572 let src_index: u64 =
573 index[usize::try_from(i).unwrap()].to_leaf().to_u32().into();
574 let dest = self.project_index(&dest, i)?;
575
576 let val = if src_index < left_len {
577 self.read_immediate(&self.project_index(&left, src_index)?)?
578 } else if src_index < left_len.strict_add(right_len) {
579 let right_idx = src_index.strict_sub(left_len);
580 self.read_immediate(&self.project_index(&right, right_idx)?)?
581 } else {
582 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`simd_shuffle_const_generic` index {0} is out-of-bounds for 2 vectors with length {1}",
src_index, dest_len))
})));throw_ub_format!(
583 "`simd_shuffle_const_generic` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
584 );
585 };
586 self.write_immediate(*val, &dest)?;
587 }
588 }
589 sym::simd_shuffle => {
590 let (left, left_len) = self.project_to_simd(&args[0])?;
591 let (right, right_len) = self.project_to_simd(&args[1])?;
592 let (index, index_len) = self.project_to_simd(&args[2])?;
593 let (dest, dest_len) = self.project_to_simd(&dest)?;
594
595 {
match (&left_len, &right_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(left_len, right_len);
596 {
match (&index_len, &dest_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(index_len, dest_len);
597
598 for i in 0..dest_len {
599 let src_index: u64 = self
600 .read_immediate(&self.project_index(&index, i)?)?
601 .to_scalar()
602 .to_u32()?
603 .into();
604 let dest = self.project_index(&dest, i)?;
605
606 let val = if src_index < left_len {
607 self.read_immediate(&self.project_index(&left, src_index)?)?
608 } else if src_index < left_len.strict_add(right_len) {
609 let right_idx = src_index.strict_sub(left_len);
610 self.read_immediate(&self.project_index(&right, right_idx)?)?
611 } else {
612 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`simd_shuffle` index {0} is out-of-bounds for 2 vectors with length {1}",
src_index, dest_len))
})));throw_ub_format!(
613 "`simd_shuffle` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
614 );
615 };
616 self.write_immediate(*val, &dest)?;
617 }
618 }
619 sym::simd_gather => {
620 let (passthru, passthru_len) = self.project_to_simd(&args[0])?;
621 let (ptrs, ptrs_len) = self.project_to_simd(&args[1])?;
622 let (mask, mask_len) = self.project_to_simd(&args[2])?;
623 let (dest, dest_len) = self.project_to_simd(&dest)?;
624
625 {
match (&dest_len, &passthru_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, passthru_len);
626 {
match (&dest_len, &ptrs_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, ptrs_len);
627 {
match (&dest_len, &mask_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, mask_len);
628
629 for i in 0..dest_len {
630 let passthru = self.read_immediate(&self.project_index(&passthru, i)?)?;
631 let ptr = self.read_immediate(&self.project_index(&ptrs, i)?)?;
632 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
633 let dest = self.project_index(&dest, i)?;
634
635 let val = if simd_element_to_bool(mask)? {
636 let place = self.deref_pointer(&ptr)?;
637 self.read_immediate(&place)?
638 } else {
639 passthru
640 };
641 self.write_immediate(*val, &dest)?;
642 }
643 }
644 sym::simd_scatter => {
645 let (value, value_len) = self.project_to_simd(&args[0])?;
646 let (ptrs, ptrs_len) = self.project_to_simd(&args[1])?;
647 let (mask, mask_len) = self.project_to_simd(&args[2])?;
648
649 {
match (&ptrs_len, &value_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(ptrs_len, value_len);
650 {
match (&ptrs_len, &mask_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(ptrs_len, mask_len);
651
652 for i in 0..ptrs_len {
653 let value = self.read_immediate(&self.project_index(&value, i)?)?;
654 let ptr = self.read_immediate(&self.project_index(&ptrs, i)?)?;
655 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
656
657 if simd_element_to_bool(mask)? {
658 let place = self.deref_pointer(&ptr)?;
659 self.write_immediate(*value, &place)?;
660 }
661 }
662 }
663 sym::simd_masked_load => {
664 let dest_layout = dest.layout;
665
666 let (mask, mask_len) = self.project_to_simd(&args[0])?;
667 let ptr = self.read_pointer(&args[1])?;
668 let (default, default_len) = self.project_to_simd(&args[2])?;
669 let (dest, dest_len) = self.project_to_simd(&dest)?;
670
671 {
match (&dest_len, &mask_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, mask_len);
672 {
match (&dest_len, &default_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, default_len);
673
674 self.check_simd_ptr_alignment(
675 ptr,
676 dest_layout,
677 generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(),
678 )?;
679
680 for i in 0..dest_len {
681 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
682 let default = self.read_immediate(&self.project_index(&default, i)?)?;
683 let dest = self.project_index(&dest, i)?;
684
685 let val = if simd_element_to_bool(mask)? {
686 let ptr = ptr.wrapping_offset(dest.layout.size * i, self);
688 let place = self.ptr_to_mplace_unaligned(ptr, dest.layout);
690 self.read_immediate(&place)?
691 } else {
692 default
693 };
694 self.write_immediate(*val, &dest)?;
695 }
696 }
697 sym::simd_masked_store => {
698 let (mask, mask_len) = self.project_to_simd(&args[0])?;
699 let ptr = self.read_pointer(&args[1])?;
700 let (vals, vals_len) = self.project_to_simd(&args[2])?;
701
702 {
match (&mask_len, &vals_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(mask_len, vals_len);
703
704 self.check_simd_ptr_alignment(
705 ptr,
706 args[2].layout,
707 generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(),
708 )?;
709
710 for i in 0..vals_len {
711 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
712 let val = self.read_immediate(&self.project_index(&vals, i)?)?;
713
714 if simd_element_to_bool(mask)? {
715 let ptr = ptr.wrapping_offset(val.layout.size * i, self);
717 let place = self.ptr_to_mplace_unaligned(ptr, val.layout);
719 self.write_immediate(*val, &place)?
720 };
721 }
722 }
723 sym::simd_fma | sym::simd_relaxed_fma => {
724 let typ = match intrinsic_name {
727 sym::simd_fma => MulAddType::Fused,
728 sym::simd_relaxed_fma => MulAddType::Nondeterministic,
729 _ => ::core::panicking::unreachable_default_msg()unreachable!(),
730 };
731
732 let (a, a_len) = self.project_to_simd(&args[0])?;
733 let (b, b_len) = self.project_to_simd(&args[1])?;
734 let (c, c_len) = self.project_to_simd(&args[2])?;
735 let (dest, dest_len) = self.project_to_simd(&dest)?;
736
737 {
match (&dest_len, &a_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, a_len);
738 {
match (&dest_len, &b_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, b_len);
739 {
match (&dest_len, &c_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, c_len);
740
741 for i in 0..dest_len {
742 let a = self.read_scalar(&self.project_index(&a, i)?)?;
743 let b = self.read_scalar(&self.project_index(&b, i)?)?;
744 let c = self.read_scalar(&self.project_index(&c, i)?)?;
745 let dest = self.project_index(&dest, i)?;
746
747 let ty::Float(float_ty) = dest.layout.ty.kind() else {
748 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("{0} operand is not a float", intrinsic_name),
Location::caller())span_bug!(self.cur_span(), "{} operand is not a float", intrinsic_name)
749 };
750
751 let val = match float_ty {
752 FloatTy::F16 => self.float_muladd::<Half>(a, b, c, typ)?,
753 FloatTy::F32 => self.float_muladd::<Single>(a, b, c, typ)?,
754 FloatTy::F64 => self.float_muladd::<Double>(a, b, c, typ)?,
755 FloatTy::F128 => self.float_muladd::<Quad>(a, b, c, typ)?,
756 };
757 self.write_scalar(val, &dest)?;
758 }
759 }
760 sym::simd_funnel_shl | sym::simd_funnel_shr => {
761 let shift_left = intrinsic_name == sym::simd_funnel_shl;
762
763 let (left, left_len) = self.project_to_simd(&args[0])?;
764 let (right, right_len) = self.project_to_simd(&args[1])?;
765 let (shift, shift_len) = self.project_to_simd(&args[2])?;
766 let (dest, dest_len) = self.project_to_simd(&dest)?;
767
768 {
match (&dest_len, &left_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, left_len);
769 {
match (&dest_len, &right_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, right_len);
770 {
match (&dest_len, &shift_len) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(dest_len, shift_len);
771
772 for i in 0..dest_len {
773 let left = self.read_immediate(&self.project_index(&left, i)?)?;
774 let right = self.read_immediate(&self.project_index(&right, i)?)?;
775 let shift_bits = self.read_immediate(&self.project_index(&shift, i)?)?;
776 let dest = self.project_index(&dest, i)?;
777
778 let result = self.funnel_shift(&left, &right, &shift_bits, shift_left)
779 .map_err_kind(|_err| {
780 ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("overflowing shift by {0} in `{1}` in lane {2}",
shift_bits, intrinsic_name, i))
})))err_ub_format!(
781 "overflowing shift by {shift_bits} in `{intrinsic_name}` in lane {i}"
782 )
783 })?;
784
785 self.write_scalar(result, &dest)?;
786 }
787 }
788
789 _ => return interp_ok(false),
791 }
792
793 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/5b7b37aefcb5b2fba3c2392bc9065b9e4602d494/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs:793",
"rustc_const_eval::interpret::intrinsics::simd",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/5b7b37aefcb5b2fba3c2392bc9065b9e4602d494/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs"),
::tracing_core::__macro_support::Option::Some(793u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::intrinsics::simd"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0:?}",
self.dump_place(&dest.clone().into())) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("{:?}", self.dump_place(&dest.clone().into()));
794 self.return_to_block(ret)?;
795 interp_ok(true)
796 }
797
798 fn fminmax_op(
799 &self,
800 op: MinMax,
801 left: &ImmTy<'tcx, M::Provenance>,
802 right: &ImmTy<'tcx, M::Provenance>,
803 ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
804 {
match (&left.layout.ty, &right.layout.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(left.layout.ty, right.layout.ty);
805 let ty::Float(float_ty) = left.layout.ty.kind() else {
806 ::rustc_span::macros::bug_impl(None,
format_args!("fmax operand is not a float"), Location::caller())bug!("fmax operand is not a float")
807 };
808 let left = left.to_scalar();
809 let right = right.to_scalar();
810 interp_ok(match float_ty {
811 FloatTy::F16 => self.float_minmax::<Half>(left, right, op)?,
812 FloatTy::F32 => self.float_minmax::<Single>(left, right, op)?,
813 FloatTy::F64 => self.float_minmax::<Double>(left, right, op)?,
814 FloatTy::F128 => self.float_minmax::<Quad>(left, right, op)?,
815 })
816 }
817
818 fn check_simd_ptr_alignment(
819 &self,
820 ptr: Pointer<Option<M::Provenance>>,
821 vector_layout: TyAndLayout<'tcx>,
822 alignment: SimdAlign,
823 ) -> InterpResult<'tcx> {
824 if !vector_layout.ty.is_simd() {
{
::core::panicking::panic_fmt(format_args!("check_simd_ptr_alignment called on non-SIMD type"));
}
};assert!(vector_layout.ty.is_simd(), "check_simd_ptr_alignment called on non-SIMD type");
828 match vector_layout.backend_repr {
829 BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => {}
830 _ => {
831 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("SIMD type has unexpected backend_repr: {0:?}",
vector_layout.backend_repr), Location::caller());span_bug!(
832 self.cur_span(),
833 "SIMD type has unexpected backend_repr: {:?}",
834 vector_layout.backend_repr
835 );
836 }
837 }
838
839 let align = match alignment {
840 ty::SimdAlign::Unaligned => {
841 return interp_ok(());
843 }
844 ty::SimdAlign::Element => {
845 vector_layout.field(self, 0).align
848 }
849 ty::SimdAlign::Vector => vector_layout.align,
850 };
851
852 self.check_ptr_align(ptr, align)
853 }
854}
855
856fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
857 if !(idx < vec_len) {
::core::panicking::panic("assertion failed: idx < vec_len")
};assert!(idx < vec_len);
858 match endianness {
859 Endian::Little => idx,
860 #[expect(clippy::arithmetic_side_effects)] Endian::Big => vec_len - 1 - idx, }
863}
864
865fn bool_to_simd_element<Prov: Provenance>(b: bool, size: Size) -> Scalar<Prov> {
866 let val = if b { -1 } else { 0 };
870 Scalar::from_int(val, size)
871}
872
873fn simd_element_to_bool<Prov: Provenance>(elem: ImmTy<'_, Prov>) -> InterpResult<'_, bool> {
874 if !#[allow(non_exhaustive_omitted_patterns)] match elem.layout.ty.kind() {
ty::Int(_) | ty::Uint(_) => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("SIMD mask element type must be an integer, but this is `{0}`",
elem.layout.ty));
}
};assert!(
875 matches!(elem.layout.ty.kind(), ty::Int(_) | ty::Uint(_)),
876 "SIMD mask element type must be an integer, but this is `{}`",
877 elem.layout.ty
878 );
879 let val = elem.to_scalar().to_int(elem.layout.size)?;
880 interp_ok(match val {
881 0 => false,
882 -1 => true,
883 _ => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("each element of a SIMD mask must be all-0-bits or all-1-bits"))
})))throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"),
884 })
885}