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, ScalarInt, SimdAlign};
7use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty};
8use rustc_span::{Symbol, 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::GenericArgsRef<'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]
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)]
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::panic("internal error: entered unreachable code")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_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("{0} operand is not a float", intrinsic_name))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_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("{0} operand is not a float", intrinsic_name))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 => self.float_round::<Half>(op, rounding)?,
149 FloatTy::F32 => self.float_round::<Single>(op, rounding)?,
150 FloatTy::F64 => self.float_round::<Double>(op, rounding)?,
151 FloatTy::F128 => self.float_round::<Quad>(op, rounding)?,
152 }
153 }
154 Op::Numeric(name) => {
155 self.numeric_intrinsic(name, op.to_scalar(), op.layout, op.layout)?
156 }
157 };
158 self.write_scalar(val, &dest)?;
159 }
160 }
161 sym::simd_add
162 | sym::simd_sub
163 | sym::simd_mul
164 | sym::simd_div
165 | sym::simd_rem
166 | sym::simd_shl
167 | sym::simd_shr
168 | sym::simd_and
169 | sym::simd_or
170 | sym::simd_xor
171 | sym::simd_eq
172 | sym::simd_ne
173 | sym::simd_lt
174 | sym::simd_le
175 | sym::simd_gt
176 | sym::simd_ge
177 | sym::simd_fmax
178 | sym::simd_fmin
179 | sym::simd_saturating_add
180 | sym::simd_saturating_sub
181 | sym::simd_arith_offset => {
182 use mir::BinOp;
183
184 let (left, left_len) = self.project_to_simd(&args[0])?;
185 let (right, right_len) = self.project_to_simd(&args[1])?;
186 let (dest, dest_len) = self.project_to_simd(&dest)?;
187
188 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);
189 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);
190
191 enum Op {
192 MirOp(BinOp),
193 SaturatingOp(BinOp),
194 FMinMax(MinMax),
195 WrappingOffset,
196 }
197 let which = match intrinsic_name {
198 sym::simd_add => Op::MirOp(BinOp::Add),
199 sym::simd_sub => Op::MirOp(BinOp::Sub),
200 sym::simd_mul => Op::MirOp(BinOp::Mul),
201 sym::simd_div => Op::MirOp(BinOp::Div),
202 sym::simd_rem => Op::MirOp(BinOp::Rem),
203 sym::simd_shl => Op::MirOp(BinOp::ShlUnchecked),
204 sym::simd_shr => Op::MirOp(BinOp::ShrUnchecked),
205 sym::simd_and => Op::MirOp(BinOp::BitAnd),
206 sym::simd_or => Op::MirOp(BinOp::BitOr),
207 sym::simd_xor => Op::MirOp(BinOp::BitXor),
208 sym::simd_eq => Op::MirOp(BinOp::Eq),
209 sym::simd_ne => Op::MirOp(BinOp::Ne),
210 sym::simd_lt => Op::MirOp(BinOp::Lt),
211 sym::simd_le => Op::MirOp(BinOp::Le),
212 sym::simd_gt => Op::MirOp(BinOp::Gt),
213 sym::simd_ge => Op::MirOp(BinOp::Ge),
214 sym::simd_fmax => Op::FMinMax(MinMax::MaximumNumber),
215 sym::simd_fmin => Op::FMinMax(MinMax::MinimumNumber),
216 sym::simd_saturating_add => Op::SaturatingOp(BinOp::Add),
217 sym::simd_saturating_sub => Op::SaturatingOp(BinOp::Sub),
218 sym::simd_arith_offset => Op::WrappingOffset,
219 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
220 };
221
222 for i in 0..dest_len {
223 let left = self.read_immediate(&self.project_index(&left, i)?)?;
224 let right = self.read_immediate(&self.project_index(&right, i)?)?;
225 let dest = self.project_index(&dest, i)?;
226 let val = match which {
227 Op::MirOp(mir_op) => {
228 let val = self.binary_op(mir_op, &left, &right).map_err_kind(|kind| {
230 match kind {
231 InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ShiftOverflow { shift_amount, .. }) => {
232 let shift_amount = match shift_amount {
234 Either::Left(v) => v.to_string(),
235 Either::Right(v) => v.to_string(),
236 };
237 ::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}")
238 }
239 kind => kind
240 }
241 })?;
242 if #[allow(non_exhaustive_omitted_patterns)] match mir_op {
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge =>
true,
_ => false,
}matches!(
243 mir_op,
244 BinOp::Eq
245 | BinOp::Ne
246 | BinOp::Lt
247 | BinOp::Le
248 | BinOp::Gt
249 | BinOp::Ge
250 ) {
251 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);
253 let val = val.to_scalar().to_bool().unwrap();
254 bool_to_simd_element(val, dest.layout.size)
255 } else {
256 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);
257 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);
258 val.to_scalar()
259 }
260 }
261 Op::SaturatingOp(mir_op) => self.saturating_arith(mir_op, &left, &right)?,
262 Op::WrappingOffset => {
263 let ptr = left.to_scalar().to_pointer(self)?;
264 let offset_count = right.to_scalar().to_target_isize(self)?;
265 let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
266
267 let pointee_size =
268 i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
269 let offset_bytes = offset_count.wrapping_mul(pointee_size);
270 let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, self);
271 Scalar::from_maybe_pointer(offset_ptr, self)
272 }
273 Op::FMinMax(op) => self.fminmax_op(op, &left, &right)?,
274 };
275 self.write_scalar(val, &dest)?;
276 }
277 }
278 sym::simd_reduce_and
279 | sym::simd_reduce_or
280 | sym::simd_reduce_xor
281 | sym::simd_reduce_any
282 | sym::simd_reduce_all
283 | sym::simd_reduce_max
284 | sym::simd_reduce_min => {
285 use mir::BinOp;
286
287 let (op, op_len) = self.project_to_simd(&args[0])?;
288
289 let imm_from_bool = |b| {
290 ImmTy::from_scalar(
291 Scalar::from_bool(b),
292 self.layout_of(self.tcx.types.bool).unwrap(),
293 )
294 };
295
296 enum Op {
297 MirOp(BinOp),
298 MirOpBool(BinOp),
299 MinMax(MinMax),
300 }
301 let which = match intrinsic_name {
302 sym::simd_reduce_and => Op::MirOp(BinOp::BitAnd),
303 sym::simd_reduce_or => Op::MirOp(BinOp::BitOr),
304 sym::simd_reduce_xor => Op::MirOp(BinOp::BitXor),
305 sym::simd_reduce_any => Op::MirOpBool(BinOp::BitOr),
306 sym::simd_reduce_all => Op::MirOpBool(BinOp::BitAnd),
307 sym::simd_reduce_max => Op::MinMax(MinMax::MaximumNumber),
308 sym::simd_reduce_min => Op::MinMax(MinMax::MinimumNumber),
309 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
310 };
311
312 let mut res = self.read_immediate(&self.project_index(&op, 0)?)?;
314 if #[allow(non_exhaustive_omitted_patterns)] match which {
Op::MirOpBool(_) => true,
_ => false,
}matches!(which, Op::MirOpBool(_)) {
315 res = imm_from_bool(simd_element_to_bool(res)?);
317 }
318 for i in 1..op_len {
319 let op = self.read_immediate(&self.project_index(&op, i)?)?;
320 res = match which {
321 Op::MirOp(mir_op) => self.binary_op(mir_op, &res, &op)?,
322 Op::MirOpBool(mir_op) => {
323 let op = imm_from_bool(simd_element_to_bool(op)?);
324 self.binary_op(mir_op, &res, &op)?
325 }
326 Op::MinMax(mmop) => {
327 if #[allow(non_exhaustive_omitted_patterns)] match res.layout.ty.kind() {
ty::Float(_) => true,
_ => false,
}matches!(res.layout.ty.kind(), ty::Float(_)) {
328 ImmTy::from_scalar(self.fminmax_op(mmop, &res, &op)?, res.layout)
329 } else {
330 let mirop = match mmop {
332 MinMax::MinimumNumber | MinMax::Minimum => BinOp::Le,
333 MinMax::MaximumNumber | MinMax::Maximum => BinOp::Ge,
334 };
335 if self.binary_op(mirop, &res, &op)?.to_scalar().to_bool()? {
336 res
337 } else {
338 op
339 }
340 }
341 }
342 };
343 }
344 self.write_immediate(*res, &dest)?;
345 }
346 sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => {
347 use mir::BinOp;
348
349 let (op, op_len) = self.project_to_simd(&args[0])?;
350 let init = self.read_immediate(&args[1])?;
351
352 let mir_op = match intrinsic_name {
353 sym::simd_reduce_add_ordered => BinOp::Add,
354 sym::simd_reduce_mul_ordered => BinOp::Mul,
355 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
356 };
357
358 let mut res = init;
359 for i in 0..op_len {
360 let op = self.read_immediate(&self.project_index(&op, i)?)?;
361 res = self.binary_op(mir_op, &res, &op)?;
362 }
363 self.write_immediate(*res, &dest)?;
364 }
365 sym::simd_select => {
366 let (mask, mask_len) = self.project_to_simd(&args[0])?;
367 let (yes, yes_len) = self.project_to_simd(&args[1])?;
368 let (no, no_len) = self.project_to_simd(&args[2])?;
369 let (dest, dest_len) = self.project_to_simd(&dest)?;
370
371 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);
372 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);
373 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);
374
375 for i in 0..dest_len {
376 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
377 let yes = self.read_immediate(&self.project_index(&yes, i)?)?;
378 let no = self.read_immediate(&self.project_index(&no, i)?)?;
379 let dest = self.project_index(&dest, i)?;
380
381 let val = if simd_element_to_bool(mask)? { yes } else { no };
382 self.write_immediate(*val, &dest)?;
383 }
384 }
385 sym::simd_select_bitmask => {
387 let mask = &args[0];
388 let (yes, yes_len) = self.project_to_simd(&args[1])?;
389 let (no, no_len) = self.project_to_simd(&args[2])?;
390 let (dest, dest_len) = self.project_to_simd(&dest)?;
391 let bitmask_len = dest_len.next_multiple_of(8);
392 if bitmask_len > 64 {
393 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!(
394 "simd_select_bitmask: vectors larger than 64 elements are currently not supported"
395 );
396 }
397
398 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);
399 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);
400
401 let mask: u64 = match mask.layout.ty.kind() {
403 ty::Uint(_) => {
404 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);
406 self.read_scalar(mask)?.to_bits(mask.layout.size)?.try_into().unwrap()
407 }
408 ty::Array(elem, _len) if elem == &self.tcx.types.u8 => {
409 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);
411 let mask = mask.assert_mem_place(); let mask_bytes =
414 self.read_bytes_ptr_strip_provenance(mask.ptr(), mask.layout.size)?;
415 let mask_size = mask.layout.size.bytes_usize();
417 let mut mask_arr = [0u8; 8];
418 match self.tcx.data_layout.endian {
419 Endian::Little => {
420 mask_arr[..mask_size].copy_from_slice(mask_bytes);
422 u64::from_le_bytes(mask_arr)
423 }
424 Endian::Big => {
425 let i = mask_arr.len().strict_sub(mask_size);
427 mask_arr[i..].copy_from_slice(mask_bytes);
428 u64::from_be_bytes(mask_arr)
429 }
430 }
431 }
432 _ => ::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),
433 };
434
435 let dest_len = u32::try_from(dest_len).unwrap();
436 for i in 0..dest_len {
437 let bit_i = simd_bitmask_index(i, dest_len, self.tcx.data_layout.endian);
438 let mask = mask & 1u64.strict_shl(bit_i);
439 let yes = self.read_immediate(&self.project_index(&yes, i.into())?)?;
440 let no = self.read_immediate(&self.project_index(&no, i.into())?)?;
441 let dest = self.project_index(&dest, i.into())?;
442
443 let val = if mask != 0 { yes } else { no };
444 self.write_immediate(*val, &dest)?;
445 }
446 }
448 sym::simd_bitmask => {
450 let (op, op_len) = self.project_to_simd(&args[0])?;
451 let bitmask_len = op_len.next_multiple_of(8);
452 if bitmask_len > 64 {
453 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!(
454 "simd_bitmask: vectors larger than 64 elements are currently not supported"
455 );
456 }
457
458 let op_len = u32::try_from(op_len).unwrap();
459 let mut res = 0u64;
460 for i in 0..op_len {
461 let op = self.read_immediate(&self.project_index(&op, i.into())?)?;
462 if simd_element_to_bool(op)? {
463 let bit_i = simd_bitmask_index(i, op_len, self.tcx.data_layout.endian);
464 res |= 1u64.strict_shl(bit_i);
465 }
466 }
467 match dest.layout.ty.kind() {
470 ty::Uint(_) => {
471 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);
473 self.write_scalar(Scalar::from_uint(res, dest.layout.size), &dest)?;
474 }
475 ty::Array(elem, _len) if elem == &self.tcx.types.u8 => {
476 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);
478 let res_size = dest.layout.size.bytes_usize();
480 let res_bytes;
481 let res_bytes_slice = match self.tcx.data_layout.endian {
482 Endian::Little => {
483 res_bytes = res.to_le_bytes();
484 &res_bytes[..res_size] }
486 Endian::Big => {
487 res_bytes = res.to_be_bytes();
488 &res_bytes[res_bytes.len().strict_sub(res_size)..] }
490 };
491 self.write_bytes_ptr(dest.ptr(), res_bytes_slice.iter().cloned())?;
492 }
493 _ => ::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),
494 }
495 }
496 sym::simd_cast
497 | sym::simd_as
498 | sym::simd_cast_ptr
499 | sym::simd_with_exposed_provenance => {
500 let (op, op_len) = self.project_to_simd(&args[0])?;
501 let (dest, dest_len) = self.project_to_simd(&dest)?;
502
503 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);
504
505 let unsafe_cast = intrinsic_name == sym::simd_cast;
506 let safe_cast = intrinsic_name == sym::simd_as;
507 let ptr_cast = intrinsic_name == sym::simd_cast_ptr;
508 let from_exposed_cast = intrinsic_name == sym::simd_with_exposed_provenance;
509
510 for i in 0..dest_len {
511 let op = self.read_immediate(&self.project_index(&op, i)?)?;
512 let dest = self.project_index(&dest, i)?;
513
514 let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
515 (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_))
517 if safe_cast || unsafe_cast =>
518 self.int_to_int_or_float(&op, dest.layout)?,
519 (ty::Float(_), ty::Float(_)) if safe_cast || unsafe_cast =>
521 self.float_to_float_or_int(&op, dest.layout)?,
522 (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
524 self.float_to_float_or_int(&op, dest.layout)?,
525 (ty::Float(_), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
527 self.float_to_int_checked(&op, dest.layout, Round::TowardZero)?
528 .ok_or_else(|| {
529 ::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!(
530 "`simd_cast` intrinsic called on {op} which cannot be represented in target type `{:?}`",
531 dest.layout.ty
532 )
533 })?
534 }
535 (ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast =>
537 self.ptr_to_ptr(&op, dest.layout)?,
538 (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
540 self.pointer_with_exposed_provenance_cast(&op, dest.layout)?,
541 _ =>
543 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!(
544 "Unsupported SIMD cast from element type {from_ty} to {to_ty}",
545 from_ty = op.layout.ty,
546 to_ty = dest.layout.ty,
547 ),
548 };
549 self.write_immediate(*val, &dest)?;
550 }
551 }
552 sym::simd_shuffle_const_generic => {
553 let (left, left_len) = self.project_to_simd(&args[0])?;
554 let (right, right_len) = self.project_to_simd(&args[1])?;
555 let (dest, dest_len) = self.project_to_simd(&dest)?;
556
557 let index = generic_args[2].expect_const().to_branch();
558 let index_len = index.len();
559
560 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);
561 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);
562
563 for i in 0..dest_len {
564 let src_index: u64 =
565 index[usize::try_from(i).unwrap()].to_leaf().to_u32().into();
566 let dest = self.project_index(&dest, i)?;
567
568 let val = if src_index < left_len {
569 self.read_immediate(&self.project_index(&left, src_index)?)?
570 } else if src_index < left_len.strict_add(right_len) {
571 let right_idx = src_index.strict_sub(left_len);
572 self.read_immediate(&self.project_index(&right, right_idx)?)?
573 } else {
574 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!(
575 "`simd_shuffle_const_generic` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
576 );
577 };
578 self.write_immediate(*val, &dest)?;
579 }
580 }
581 sym::simd_shuffle => {
582 let (left, left_len) = self.project_to_simd(&args[0])?;
583 let (right, right_len) = self.project_to_simd(&args[1])?;
584 let (index, index_len) = self.project_to_simd(&args[2])?;
585 let (dest, dest_len) = self.project_to_simd(&dest)?;
586
587 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);
588 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);
589
590 for i in 0..dest_len {
591 let src_index: u64 = self
592 .read_immediate(&self.project_index(&index, i)?)?
593 .to_scalar()
594 .to_u32()?
595 .into();
596 let dest = self.project_index(&dest, i)?;
597
598 let val = if src_index < left_len {
599 self.read_immediate(&self.project_index(&left, src_index)?)?
600 } else if src_index < left_len.strict_add(right_len) {
601 let right_idx = src_index.strict_sub(left_len);
602 self.read_immediate(&self.project_index(&right, right_idx)?)?
603 } else {
604 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!(
605 "`simd_shuffle` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
606 );
607 };
608 self.write_immediate(*val, &dest)?;
609 }
610 }
611 sym::simd_gather => {
612 let (passthru, passthru_len) = self.project_to_simd(&args[0])?;
613 let (ptrs, ptrs_len) = self.project_to_simd(&args[1])?;
614 let (mask, mask_len) = self.project_to_simd(&args[2])?;
615 let (dest, dest_len) = self.project_to_simd(&dest)?;
616
617 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);
618 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);
619 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);
620
621 for i in 0..dest_len {
622 let passthru = self.read_immediate(&self.project_index(&passthru, i)?)?;
623 let ptr = self.read_immediate(&self.project_index(&ptrs, i)?)?;
624 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
625 let dest = self.project_index(&dest, i)?;
626
627 let val = if simd_element_to_bool(mask)? {
628 let place = self.deref_pointer(&ptr)?;
629 self.read_immediate(&place)?
630 } else {
631 passthru
632 };
633 self.write_immediate(*val, &dest)?;
634 }
635 }
636 sym::simd_scatter => {
637 let (value, value_len) = self.project_to_simd(&args[0])?;
638 let (ptrs, ptrs_len) = self.project_to_simd(&args[1])?;
639 let (mask, mask_len) = self.project_to_simd(&args[2])?;
640
641 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);
642 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);
643
644 for i in 0..ptrs_len {
645 let value = self.read_immediate(&self.project_index(&value, i)?)?;
646 let ptr = self.read_immediate(&self.project_index(&ptrs, i)?)?;
647 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
648
649 if simd_element_to_bool(mask)? {
650 let place = self.deref_pointer(&ptr)?;
651 self.write_immediate(*value, &place)?;
652 }
653 }
654 }
655 sym::simd_masked_load => {
656 let dest_layout = dest.layout;
657
658 let (mask, mask_len) = self.project_to_simd(&args[0])?;
659 let ptr = self.read_pointer(&args[1])?;
660 let (default, default_len) = self.project_to_simd(&args[2])?;
661 let (dest, dest_len) = self.project_to_simd(&dest)?;
662
663 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);
664 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);
665
666 self.check_simd_ptr_alignment(
667 ptr,
668 dest_layout,
669 generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(),
670 )?;
671
672 for i in 0..dest_len {
673 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
674 let default = self.read_immediate(&self.project_index(&default, i)?)?;
675 let dest = self.project_index(&dest, i)?;
676
677 let val = if simd_element_to_bool(mask)? {
678 let ptr = ptr.wrapping_offset(dest.layout.size * i, self);
680 let place = self.ptr_to_mplace_unaligned(ptr, dest.layout);
682 self.read_immediate(&place)?
683 } else {
684 default
685 };
686 self.write_immediate(*val, &dest)?;
687 }
688 }
689 sym::simd_masked_store => {
690 let (mask, mask_len) = self.project_to_simd(&args[0])?;
691 let ptr = self.read_pointer(&args[1])?;
692 let (vals, vals_len) = self.project_to_simd(&args[2])?;
693
694 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);
695
696 self.check_simd_ptr_alignment(
697 ptr,
698 args[2].layout,
699 generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(),
700 )?;
701
702 for i in 0..vals_len {
703 let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
704 let val = self.read_immediate(&self.project_index(&vals, i)?)?;
705
706 if simd_element_to_bool(mask)? {
707 let ptr = ptr.wrapping_offset(val.layout.size * i, self);
709 let place = self.ptr_to_mplace_unaligned(ptr, val.layout);
711 self.write_immediate(*val, &place)?
712 };
713 }
714 }
715 sym::simd_fma | sym::simd_relaxed_fma => {
716 let typ = match intrinsic_name {
719 sym::simd_fma => MulAddType::Fused,
720 sym::simd_relaxed_fma => MulAddType::Nondeterministic,
721 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
722 };
723
724 let (a, a_len) = self.project_to_simd(&args[0])?;
725 let (b, b_len) = self.project_to_simd(&args[1])?;
726 let (c, c_len) = self.project_to_simd(&args[2])?;
727 let (dest, dest_len) = self.project_to_simd(&dest)?;
728
729 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);
730 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);
731 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);
732
733 for i in 0..dest_len {
734 let a = self.read_scalar(&self.project_index(&a, i)?)?;
735 let b = self.read_scalar(&self.project_index(&b, i)?)?;
736 let c = self.read_scalar(&self.project_index(&c, i)?)?;
737 let dest = self.project_index(&dest, i)?;
738
739 let ty::Float(float_ty) = dest.layout.ty.kind() else {
740 ::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)
741 };
742
743 let val = match float_ty {
744 FloatTy::F16 => self.float_muladd::<Half>(a, b, c, typ)?,
745 FloatTy::F32 => self.float_muladd::<Single>(a, b, c, typ)?,
746 FloatTy::F64 => self.float_muladd::<Double>(a, b, c, typ)?,
747 FloatTy::F128 => self.float_muladd::<Quad>(a, b, c, typ)?,
748 };
749 self.write_scalar(val, &dest)?;
750 }
751 }
752 sym::simd_funnel_shl | sym::simd_funnel_shr => {
753 let (left, _) = self.project_to_simd(&args[0])?;
754 let (right, _) = self.project_to_simd(&args[1])?;
755 let (shift, _) = self.project_to_simd(&args[2])?;
756 let (dest, _) = self.project_to_simd(&dest)?;
757
758 let (len, elem_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
759 let (elem_size, _signed) = elem_ty.int_size_and_signed(*self.tcx);
760 let elem_size_bits = u128::from(elem_size.bits());
761
762 let is_left = intrinsic_name == sym::simd_funnel_shl;
763
764 for i in 0..len {
765 let left =
766 self.read_scalar(&self.project_index(&left, i)?)?.to_bits(elem_size)?;
767 let right =
768 self.read_scalar(&self.project_index(&right, i)?)?.to_bits(elem_size)?;
769 let shift_bits =
770 self.read_scalar(&self.project_index(&shift, i)?)?.to_bits(elem_size)?;
771
772 if shift_bits >= elem_size_bits {
773 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!(
774 "overflowing shift by {shift_bits} in `{intrinsic_name}` in lane {i}"
775 );
776 }
777 let inv_shift_bits = u32::try_from(elem_size_bits - shift_bits).unwrap();
778
779 let result_bits = if is_left {
794 (left << shift_bits) | right.unbounded_shr(inv_shift_bits)
795 } else {
796 left.unbounded_shl(inv_shift_bits) | (right >> shift_bits)
797 };
798 let (result, _overflow) = ScalarInt::truncate_from_uint(result_bits, elem_size);
799
800 let dest = self.project_index(&dest, i)?;
801 self.write_scalar(result, &dest)?;
802 }
803 }
804
805 _ => return interp_ok(false),
807 }
808
809 {
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:809",
"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(809u32),
::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()));
810 self.return_to_block(ret)?;
811 interp_ok(true)
812 }
813
814 fn fminmax_op(
815 &self,
816 op: MinMax,
817 left: &ImmTy<'tcx, M::Provenance>,
818 right: &ImmTy<'tcx, M::Provenance>,
819 ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
820 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);
821 let ty::Float(float_ty) = left.layout.ty.kind() else {
822 ::rustc_middle::util::bug::bug_fmt(format_args!("fmax operand is not a float"))bug!("fmax operand is not a float")
823 };
824 let left = left.to_scalar();
825 let right = right.to_scalar();
826 interp_ok(match float_ty {
827 FloatTy::F16 => self.float_minmax::<Half>(left, right, op)?,
828 FloatTy::F32 => self.float_minmax::<Single>(left, right, op)?,
829 FloatTy::F64 => self.float_minmax::<Double>(left, right, op)?,
830 FloatTy::F128 => self.float_minmax::<Quad>(left, right, op)?,
831 })
832 }
833
834 fn check_simd_ptr_alignment(
835 &self,
836 ptr: Pointer<Option<M::Provenance>>,
837 vector_layout: TyAndLayout<'tcx>,
838 alignment: SimdAlign,
839 ) -> InterpResult<'tcx> {
840 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");
844 match vector_layout.backend_repr {
845 BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => {}
846 _ => {
847 ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("SIMD type has unexpected backend_repr: {0:?}",
vector_layout.backend_repr));span_bug!(
848 self.cur_span(),
849 "SIMD type has unexpected backend_repr: {:?}",
850 vector_layout.backend_repr
851 );
852 }
853 }
854
855 let align = match alignment {
856 ty::SimdAlign::Unaligned => {
857 return interp_ok(());
859 }
860 ty::SimdAlign::Element => {
861 vector_layout.field(self, 0).align.abi
864 }
865 ty::SimdAlign::Vector => vector_layout.align.abi,
866 };
867
868 self.check_ptr_align(ptr, align)
869 }
870}
871
872fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
873 if !(idx < vec_len) {
::core::panicking::panic("assertion failed: idx < vec_len")
};assert!(idx < vec_len);
874 match endianness {
875 Endian::Little => idx,
876 #[expect(clippy::arithmetic_side_effects)] Endian::Big => vec_len - 1 - idx, }
879}
880
881fn bool_to_simd_element<Prov: Provenance>(b: bool, size: Size) -> Scalar<Prov> {
882 let val = if b { -1 } else { 0 };
886 Scalar::from_int(val, size)
887}
888
889fn simd_element_to_bool<Prov: Provenance>(elem: ImmTy<'_, Prov>) -> InterpResult<'_, bool> {
890 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!(
891 matches!(elem.layout.ty.kind(), ty::Int(_) | ty::Uint(_)),
892 "SIMD mask element type must be an integer, but this is `{}`",
893 elem.layout.ty
894 );
895 let val = elem.to_scalar().to_int(elem.layout.size)?;
896 interp_ok(match val {
897 0 => false,
898 -1 => true,
899 _ => 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"),
900 })
901}