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