1use std::cmp::{self, Ordering};
5
6use hir_def::{attrs::AttrFlags, signatures::FunctionSignature};
7use rustc_abi::ExternAbi;
8use rustc_type_ir::inherent::{GenericArgs as _, IntoKind, SliceLike, Ty as _};
9use stdx::never;
10
11use crate::{
12 drop::{DropGlue, has_drop_glue},
13 mir::eval::{
14 Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, Interval,
15 IntervalAndTy, IntervalOrOwned, IsSigned, ItemContainerId, Layout, Locals, Lookup,
16 MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, from_bytes, not_supported, pad16,
17 },
18 next_solver::Region,
19};
20
21mod simd;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24enum EvalLangItem {
25 BeginPanic,
26 SliceLen,
27 DropInPlace,
28}
29
30impl<'a, 'db> Evaluator<'a, 'db> {
31 pub(super) fn detect_and_exec_special_function(
32 &mut self,
33 def: FunctionId,
34 args: &[IntervalAndTy<'db>],
35 generic_args: GenericArgs<'db>,
36 locals: &Locals<'a, 'db>,
37 destination: Interval,
38 span: MirSpan,
39 ) -> Result<'db, bool> {
40 if self.not_special_fn_cache.borrow().contains(&def) {
41 return Ok(false);
42 }
43
44 let function_data = FunctionSignature::of(self.db, def);
45 let attrs = AttrFlags::query(self.db, def.into());
46 let is_intrinsic = FunctionSignature::is_intrinsic(self.db, def);
47
48 if is_intrinsic {
49 return self.exec_intrinsic(
50 function_data.name.as_str(),
51 args,
52 generic_args,
53 destination,
54 locals,
55 span,
56 !function_data.has_body()
57 || attrs.contains(AttrFlags::RUSTC_INTRINSIC_MUST_BE_OVERRIDDEN),
58 );
59 }
60 let is_extern_c = match def.lookup(self.db).container {
61 hir_def::ItemContainerId::ExternBlockId(block) => {
62 matches!(block.abi(self.db), ExternAbi::C { .. })
63 }
64 _ => false,
65 };
66 if is_extern_c {
67 return self
68 .exec_extern_c(
69 function_data.name.as_str(),
70 args,
71 generic_args,
72 destination,
73 locals,
74 span,
75 )
76 .map(|()| true);
77 }
78
79 if attrs.intersects(
80 AttrFlags::RUSTC_ALLOCATOR
81 | AttrFlags::RUSTC_DEALLOCATOR
82 | AttrFlags::RUSTC_REALLOCATOR
83 | AttrFlags::RUSTC_ALLOCATOR_ZEROED,
84 ) {
85 self.exec_alloc_fn(attrs, args, destination)?;
86 return Ok(true);
87 }
88 if let Some(it) = self.detect_lang_function(def) {
89 let result = self.exec_lang_item(it, generic_args, args, locals, span)?;
90 destination.write_from_bytes(self, &result)?;
91 return Ok(true);
92 }
93 if let ItemContainerId::TraitId(t) = def.lookup(self.db).container
94 && Some(t) == self.lang_items().Clone
95 {
96 let [self_ty] = generic_args.as_slice() else {
97 not_supported!("wrong generic arg count for clone");
98 };
99 let Some(self_ty) = self_ty.ty() else {
100 not_supported!("wrong generic arg kind for clone");
101 };
102 if matches!(self_ty.kind(), TyKind::FnPtr(..) | TyKind::Tuple(..) | TyKind::Closure(..))
104 {
105 self.exec_clone(def, args, self_ty, locals, destination, span)?;
106 return Ok(true);
107 }
108 return Ok(false);
110 }
111 self.not_special_fn_cache.borrow_mut().insert(def);
112 Ok(false)
113 }
114
115 pub(super) fn detect_and_redirect_special_function(
116 &mut self,
117 def: FunctionId,
118 ) -> Result<'db, Option<FunctionId>> {
119 if Some(def) == self.lang_items().PanicFmt {
121 let Some(const_panic_fmt) = self.lang_items().ConstPanicFmt else {
122 not_supported!("const_panic_fmt lang item not found or not a function");
123 };
124 return Ok(Some(const_panic_fmt));
125 }
126 Ok(None)
127 }
128
129 fn exec_clone(
131 &mut self,
132 def: FunctionId,
133 args: &[IntervalAndTy<'db>],
134 self_ty: Ty<'db>,
135 locals: &Locals<'a, 'db>,
136 destination: Interval,
137 span: MirSpan,
138 ) -> Result<'db, ()> {
139 match self_ty.kind() {
140 TyKind::FnPtr(..) => {
141 let [arg] = args else {
142 not_supported!("wrong arg count for clone");
143 };
144 let addr = Address::from_bytes(arg.get(self)?)?;
145 return destination
146 .write_from_interval(self, Interval { addr, size: destination.size });
147 }
148 TyKind::Closure(_, closure_args) => self.exec_clone(
149 def,
150 args,
151 closure_args.as_closure().tupled_upvars_ty(),
152 locals,
153 destination,
154 span,
155 )?,
156 TyKind::Tuple(subst) => {
157 let [arg] = args else {
158 not_supported!("wrong arg count for clone");
159 };
160 let addr = Address::from_bytes(arg.get(self)?)?;
161 let layout = self.layout(self_ty)?;
162 self.exec_clone_for_fields(
163 subst.iter(),
164 layout,
165 addr,
166 def,
167 locals,
168 destination,
169 span,
170 )?;
171 }
172 _ => {
173 self.exec_fn_with_args(
174 def,
175 args,
176 GenericArgs::new_from_slice(&[self_ty.into()]),
177 locals,
178 destination,
179 None,
180 span,
181 )?;
182 }
183 }
184 Ok(())
185 }
186
187 fn exec_clone_for_fields(
188 &mut self,
189 ty_iter: impl Iterator<Item = Ty<'db>>,
190 layout: Arc<Layout>,
191 addr: Address,
192 def: FunctionId,
193 locals: &Locals<'a, 'db>,
194 destination: Interval,
195 span: MirSpan,
196 ) -> Result<'db, ()> {
197 for (i, ty) in ty_iter.enumerate() {
198 let size = self.layout(ty)?.size.bytes_usize();
199 let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
200 let arg = IntervalAndTy {
201 interval: Interval { addr: tmp, size: self.ptr_size() },
202 ty: Ty::new_ref(
203 self.interner(),
204 Region::error(self.interner()),
205 ty,
206 Mutability::Not,
207 ),
208 };
209 let offset = layout.fields.offset(i).bytes_usize();
210 self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
211 self.exec_clone(
212 def,
213 &[arg],
214 ty,
215 locals,
216 destination.slice(offset..offset + size),
217 span,
218 )?;
219 }
220 Ok(())
221 }
222
223 fn exec_alloc_fn(
224 &mut self,
225 alloc_fn: AttrFlags,
226 args: &[IntervalAndTy<'db>],
227 destination: Interval,
228 ) -> Result<'db, ()> {
229 match alloc_fn {
230 _ if alloc_fn
231 .intersects(AttrFlags::RUSTC_ALLOCATOR_ZEROED | AttrFlags::RUSTC_ALLOCATOR) =>
232 {
233 let [size, align] = args else {
234 return Err(MirEvalError::InternalError(
235 "rustc_allocator args are not provided".into(),
236 ));
237 };
238 let size = from_bytes!(usize, size.get(self)?);
239 let align = from_bytes!(usize, align.get(self)?);
240 let result = self.heap_allocate(size, align)?;
241 destination.write_from_bytes(self, &result.to_bytes())?;
242 }
243 _ if alloc_fn.contains(AttrFlags::RUSTC_DEALLOCATOR) => { }
244 _ if alloc_fn.contains(AttrFlags::RUSTC_REALLOCATOR) => {
245 let [ptr, old_size, align, new_size] = args else {
246 return Err(MirEvalError::InternalError(
247 "rustc_allocator args are not provided".into(),
248 ));
249 };
250 let old_size = from_bytes!(usize, old_size.get(self)?);
251 let new_size = from_bytes!(usize, new_size.get(self)?);
252 if old_size >= new_size {
253 destination.write_from_interval(self, ptr.interval)?;
254 } else {
255 let ptr = Address::from_bytes(ptr.get(self)?)?;
256 let align = from_bytes!(usize, align.get(self)?);
257 let result = self.heap_allocate(new_size, align)?;
258 Interval { addr: result, size: old_size }
259 .write_from_interval(self, Interval { addr: ptr, size: old_size })?;
260 destination.write_from_bytes(self, &result.to_bytes())?;
261 }
262 }
263 _ => not_supported!("unknown alloc function"),
264 }
265 Ok(())
266 }
267
268 fn detect_lang_function(&self, def: FunctionId) -> Option<EvalLangItem> {
269 use EvalLangItem::*;
270 let lang_items = self.lang_items();
271 let attrs = AttrFlags::query(self.db, def.into());
272
273 if attrs.contains(AttrFlags::RUSTC_CONST_PANIC_STR) {
274 return Some(BeginPanic);
276 }
277
278 if let Some((_, candidate)) = [
281 (lang_items.BeginPanic, BeginPanic),
282 (lang_items.SliceLen, SliceLen),
283 (lang_items.DropInPlace, DropInPlace),
284 ]
285 .iter()
286 .find(|&(candidate, _)| candidate == Some(def))
287 {
288 return Some(candidate);
289 }
290
291 None
292 }
293
294 fn exec_lang_item(
295 &mut self,
296 it: EvalLangItem,
297 generic_args: GenericArgs<'db>,
298 args: &[IntervalAndTy<'db>],
299 locals: &Locals<'a, 'db>,
300 span: MirSpan,
301 ) -> Result<'db, Vec<u8>> {
302 use EvalLangItem::*;
303 let mut args = args.iter();
304 match it {
305 BeginPanic => {
306 let mut arg = args
307 .next()
308 .ok_or(MirEvalError::InternalError(
309 "argument of BeginPanic is not provided".into(),
310 ))?
311 .clone();
312 while let TyKind::Ref(_, ty, _) = arg.ty.kind() {
313 if ty.is_str() {
314 let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size());
315 let len = from_bytes!(usize, metadata);
316
317 return {
318 Err(MirEvalError::Panic(
319 std::str::from_utf8(
320 self.read_memory(Address::from_bytes(pointee)?, len)?,
321 )
322 .unwrap()
323 .to_owned(),
324 ))
325 };
326 }
327 let size = self.size_of_sized(ty, locals, "begin panic arg")?;
328 let pointee = arg.interval.get(self)?;
329 arg = IntervalAndTy {
330 interval: Interval::new(Address::from_bytes(pointee)?, size),
331 ty,
332 };
333 }
334 Err(MirEvalError::Panic(format!("unknown-panic-payload: {:?}", arg.ty.kind())))
335 }
336 SliceLen => {
337 let arg = args.next().ok_or(MirEvalError::InternalError(
338 "argument of <[T]>::len() is not provided".into(),
339 ))?;
340 let arg = arg.get(self)?;
341 let ptr_size = arg.len() / 2;
342 Ok(arg[ptr_size..].into())
343 }
344 DropInPlace => {
345 let ty = generic_args.as_slice().first().and_then(|it| it.ty()).ok_or(
346 MirEvalError::InternalError(
347 "generic argument of drop_in_place is not provided".into(),
348 ),
349 )?;
350 let arg = args.next().ok_or(MirEvalError::InternalError(
351 "argument of drop_in_place is not provided".into(),
352 ))?;
353 let arg = arg.interval.get(self)?.to_owned();
354 self.run_drop_glue_deep(
355 ty,
356 locals,
357 Address::from_bytes(&arg[0..self.ptr_size()])?,
358 &arg[self.ptr_size()..],
359 span,
360 )?;
361 Ok(vec![])
362 }
363 }
364 }
365
366 fn exec_syscall(
367 &mut self,
368 id: i64,
369 args: &[IntervalAndTy<'db>],
370 destination: Interval,
371 _locals: &Locals<'a, 'db>,
372 _span: MirSpan,
373 ) -> Result<'db, ()> {
374 match id {
375 318 => {
376 let [buf, len, _flags] = args else {
378 return Err(MirEvalError::InternalError(
379 "SYS_getrandom args are not provided".into(),
380 ));
381 };
382 let addr = Address::from_bytes(buf.get(self)?)?;
383 let size = from_bytes!(usize, len.get(self)?);
384 for i in 0..size {
385 let rand_byte = self.random_state.rand_u64() as u8;
386 self.write_memory(addr.offset(i), &[rand_byte])?;
387 }
388 destination.write_from_interval(self, len.interval)
389 }
390 _ => {
391 not_supported!("Unknown syscall id {id:?}")
392 }
393 }
394 }
395
396 fn exec_extern_c(
397 &mut self,
398 as_str: &str,
399 args: &[IntervalAndTy<'db>],
400 _generic_args: GenericArgs<'db>,
401 destination: Interval,
402 locals: &Locals<'a, 'db>,
403 span: MirSpan,
404 ) -> Result<'db, ()> {
405 match as_str {
406 "memcmp" => {
407 let [ptr1, ptr2, size] = args else {
408 return Err(MirEvalError::InternalError("memcmp args are not provided".into()));
409 };
410 let addr1 = Address::from_bytes(ptr1.get(self)?)?;
411 let addr2 = Address::from_bytes(ptr2.get(self)?)?;
412 let size = from_bytes!(usize, size.get(self)?);
413 let slice1 = self.read_memory(addr1, size)?;
414 let slice2 = self.read_memory(addr2, size)?;
415 let r: i128 = match slice1.cmp(slice2) {
416 cmp::Ordering::Less => -1,
417 cmp::Ordering::Equal => 0,
418 cmp::Ordering::Greater => 1,
419 };
420 destination.write_from_bytes(self, &r.to_le_bytes()[..destination.size])
421 }
422 "write" => {
423 let [fd, ptr, len] = args else {
424 return Err(MirEvalError::InternalError(
425 "libc::write args are not provided".into(),
426 ));
427 };
428 let fd = u128::from_le_bytes(pad16(fd.get(self)?, IsSigned::No));
429 let interval = Interval {
430 addr: Address::from_bytes(ptr.get(self)?)?,
431 size: from_bytes!(usize, len.get(self)?),
432 };
433 match fd {
434 1 => {
435 self.write_to_stdout(interval)?;
436 }
437 2 => {
438 self.write_to_stderr(interval)?;
439 }
440 _ => not_supported!("write to arbitrary file descriptor"),
441 }
442 destination.write_from_interval(self, len.interval)?;
443 Ok(())
444 }
445 "pthread_key_create" => {
446 let key = self.thread_local_storage.create_key();
447 let Some(arg0) = args.first() else {
448 return Err(MirEvalError::InternalError(
449 "pthread_key_create arg0 is not provided".into(),
450 ));
451 };
452 let arg0_addr = Address::from_bytes(arg0.get(self)?)?;
453 let key_ty = if let Some((ty, ..)) = arg0.ty.as_reference_or_ptr() {
454 ty
455 } else {
456 return Err(MirEvalError::InternalError(
457 "pthread_key_create arg0 is not a pointer".into(),
458 ));
459 };
460 let arg0_interval = Interval::new(
461 arg0_addr,
462 self.size_of_sized(key_ty, locals, "pthread_key_create key arg")?,
463 );
464 arg0_interval.write_from_bytes(self, &key.to_le_bytes()[0..arg0_interval.size])?;
465 destination.write_from_bytes(self, &0u64.to_le_bytes()[0..destination.size])?;
467 Ok(())
468 }
469 "pthread_getspecific" => {
470 let Some(arg0) = args.first() else {
471 return Err(MirEvalError::InternalError(
472 "pthread_getspecific arg0 is not provided".into(),
473 ));
474 };
475 let key = from_bytes!(usize, &pad16(arg0.get(self)?, IsSigned::No)[0..8]);
476 let value = self.thread_local_storage.get_key(key)?;
477 destination.write_from_bytes(self, &value.to_le_bytes()[0..destination.size])?;
478 Ok(())
479 }
480 "pthread_setspecific" => {
481 let Some(arg0) = args.first() else {
482 return Err(MirEvalError::InternalError(
483 "pthread_setspecific arg0 is not provided".into(),
484 ));
485 };
486 let key = from_bytes!(usize, &pad16(arg0.get(self)?, IsSigned::No)[0..8]);
487 let Some(arg1) = args.get(1) else {
488 return Err(MirEvalError::InternalError(
489 "pthread_setspecific arg1 is not provided".into(),
490 ));
491 };
492 let value = from_bytes!(u128, pad16(arg1.get(self)?, IsSigned::No));
493 self.thread_local_storage.set_key(key, value)?;
494 destination.write_from_bytes(self, &0u64.to_le_bytes()[0..destination.size])?;
496 Ok(())
497 }
498 "pthread_key_delete" => {
499 destination.write_from_bytes(self, &0u64.to_le_bytes()[0..destination.size])?;
502 Ok(())
503 }
504 "syscall" => {
505 let Some((id, rest)) = args.split_first() else {
506 return Err(MirEvalError::InternalError("syscall arg1 is not provided".into()));
507 };
508 let id = from_bytes!(i64, id.get(self)?);
509 self.exec_syscall(id, rest, destination, locals, span)
510 }
511 "sched_getaffinity" => {
512 let [_pid, _set_size, set] = args else {
513 return Err(MirEvalError::InternalError(
514 "sched_getaffinity args are not provided".into(),
515 ));
516 };
517 let set = Address::from_bytes(set.get(self)?)?;
518 self.write_memory(set, &[1])?;
520 self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
522 Ok(())
523 }
524 "getenv" => {
525 let [name] = args else {
526 return Err(MirEvalError::InternalError("getenv args are not provided".into()));
527 };
528 let mut name_buf = vec![];
529 let name = {
530 let mut index = Address::from_bytes(name.get(self)?)?;
531 loop {
532 let byte = self.read_memory(index, 1)?[0];
533 index = index.offset(1);
534 if byte == 0 {
535 break;
536 }
537 name_buf.push(byte);
538 }
539 String::from_utf8_lossy(&name_buf)
540 };
541 let value = self.crate_id.env(self.db).get(&name);
542 match value {
543 None => {
544 self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
546 }
547 Some(mut value) => {
548 value.push('\0');
549 let addr = self.heap_allocate(value.len(), 1)?;
550 self.write_memory(addr, value.as_bytes())?;
551 self.write_memory(destination.addr, &addr.to_bytes())?;
552 }
553 }
554 Ok(())
555 }
556 _ => not_supported!("unknown external function {as_str}"),
557 }
558 }
559
560 fn exec_intrinsic(
561 &mut self,
562 name: &str,
563 args: &[IntervalAndTy<'db>],
564 generic_args: GenericArgs<'db>,
565 destination: Interval,
566 locals: &Locals<'a, 'db>,
567 span: MirSpan,
568 needs_override: bool,
569 ) -> Result<'db, bool> {
570 if let Some(name) = name.strip_prefix("atomic_") {
571 return self
572 .exec_atomic_intrinsic(name, args, generic_args, destination, locals, span)
573 .map(|()| true);
574 }
575 if let Some(name) = name.strip_prefix("simd_") {
576 return self
577 .exec_simd_intrinsic(name, args, generic_args, destination, locals, span)
578 .map(|()| true);
579 }
580 if let Some(name) = name.strip_suffix("f64") {
582 let result = match name {
583 "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs"
584 | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => {
585 let [arg] = args else {
586 return Err(MirEvalError::InternalError(
587 "f64 intrinsic signature doesn't match fn (f64) -> f64".into(),
588 ));
589 };
590 let arg = from_bytes!(f64, arg.get(self)?);
591 match name {
592 "sqrt" => arg.sqrt(),
593 "sin" => arg.sin(),
594 "cos" => arg.cos(),
595 "exp" => arg.exp(),
596 "exp2" => arg.exp2(),
597 "log" => arg.ln(),
598 "log10" => arg.log10(),
599 "log2" => arg.log2(),
600 "fabs" => arg.abs(),
601 "floor" => arg.floor(),
602 "ceil" => arg.ceil(),
603 "trunc" => arg.trunc(),
604 "rint" => arg.round(),
606 "nearbyint" => arg.round(),
607 "round" => arg.round(),
608 "roundeven" => arg.round(),
609 _ => unreachable!(),
610 }
611 }
612 "pow" | "minnum" | "maxnum" | "copysign" => {
613 let [arg1, arg2] = args else {
614 return Err(MirEvalError::InternalError(
615 "f64 intrinsic signature doesn't match fn (f64, f64) -> f64".into(),
616 ));
617 };
618 let arg1 = from_bytes!(f64, arg1.get(self)?);
619 let arg2 = from_bytes!(f64, arg2.get(self)?);
620 match name {
621 "pow" => arg1.powf(arg2),
622 "minnum" => arg1.min(arg2),
623 "maxnum" => arg1.max(arg2),
624 "copysign" => arg1.copysign(arg2),
625 _ => unreachable!(),
626 }
627 }
628 "powi" => {
629 let [arg1, arg2] = args else {
630 return Err(MirEvalError::InternalError(
631 "powif64 signature doesn't match fn (f64, i32) -> f64".into(),
632 ));
633 };
634 let arg1 = from_bytes!(f64, arg1.get(self)?);
635 let arg2 = from_bytes!(i32, arg2.get(self)?);
636 arg1.powi(arg2)
637 }
638 "fma" => {
639 let [arg1, arg2, arg3] = args else {
640 return Err(MirEvalError::InternalError(
641 "fmaf64 signature doesn't match fn (f64, f64, f64) -> f64".into(),
642 ));
643 };
644 let arg1 = from_bytes!(f64, arg1.get(self)?);
645 let arg2 = from_bytes!(f64, arg2.get(self)?);
646 let arg3 = from_bytes!(f64, arg3.get(self)?);
647 arg1.mul_add(arg2, arg3)
648 }
649 _ => not_supported!("unknown f64 intrinsic {name}"),
650 };
651 return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true);
652 }
653 if let Some(name) = name.strip_suffix("f32") {
654 let result = match name {
655 "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs"
656 | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => {
657 let [arg] = args else {
658 return Err(MirEvalError::InternalError(
659 "f32 intrinsic signature doesn't match fn (f32) -> f32".into(),
660 ));
661 };
662 let arg = from_bytes!(f32, arg.get(self)?);
663 match name {
664 "sqrt" => arg.sqrt(),
665 "sin" => arg.sin(),
666 "cos" => arg.cos(),
667 "exp" => arg.exp(),
668 "exp2" => arg.exp2(),
669 "log" => arg.ln(),
670 "log10" => arg.log10(),
671 "log2" => arg.log2(),
672 "fabs" => arg.abs(),
673 "floor" => arg.floor(),
674 "ceil" => arg.ceil(),
675 "trunc" => arg.trunc(),
676 "rint" => arg.round(),
678 "nearbyint" => arg.round(),
679 "round" => arg.round(),
680 "roundeven" => arg.round(),
681 _ => unreachable!(),
682 }
683 }
684 "pow" | "minnum" | "maxnum" | "copysign" => {
685 let [arg1, arg2] = args else {
686 return Err(MirEvalError::InternalError(
687 "f32 intrinsic signature doesn't match fn (f32, f32) -> f32".into(),
688 ));
689 };
690 let arg1 = from_bytes!(f32, arg1.get(self)?);
691 let arg2 = from_bytes!(f32, arg2.get(self)?);
692 match name {
693 "pow" => arg1.powf(arg2),
694 "minnum" => arg1.min(arg2),
695 "maxnum" => arg1.max(arg2),
696 "copysign" => arg1.copysign(arg2),
697 _ => unreachable!(),
698 }
699 }
700 "powi" => {
701 let [arg1, arg2] = args else {
702 return Err(MirEvalError::InternalError(
703 "powif32 signature doesn't match fn (f32, i32) -> f32".into(),
704 ));
705 };
706 let arg1 = from_bytes!(f32, arg1.get(self)?);
707 let arg2 = from_bytes!(i32, arg2.get(self)?);
708 arg1.powi(arg2)
709 }
710 "fma" => {
711 let [arg1, arg2, arg3] = args else {
712 return Err(MirEvalError::InternalError(
713 "fmaf32 signature doesn't match fn (f32, f32, f32) -> f32".into(),
714 ));
715 };
716 let arg1 = from_bytes!(f32, arg1.get(self)?);
717 let arg2 = from_bytes!(f32, arg2.get(self)?);
718 let arg3 = from_bytes!(f32, arg3.get(self)?);
719 arg1.mul_add(arg2, arg3)
720 }
721 _ => not_supported!("unknown f32 intrinsic {name}"),
722 };
723 return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true);
724 }
725 match name {
726 "size_of" => {
727 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
728 return Err(MirEvalError::InternalError(
729 "size_of generic arg is not provided".into(),
730 ));
731 };
732 let size = self.size_of_sized(ty, locals, "size_of arg")?;
733 destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size])
734 }
735 "align_of" => {
736 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
737 return Err(MirEvalError::InternalError(
738 "align_of generic arg is not provided".into(),
739 ));
740 };
741 let align = self.layout(ty)?.align.bytes();
742 destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size])
743 }
744 "size_of_val" => {
745 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
746 return Err(MirEvalError::InternalError(
747 "size_of_val generic arg is not provided".into(),
748 ));
749 };
750 let [arg] = args else {
751 return Err(MirEvalError::InternalError(
752 "size_of_val args are not provided".into(),
753 ));
754 };
755 if let Some((size, _)) = self.size_align_of(ty, locals)? {
756 destination.write_from_bytes(self, &size.to_le_bytes())
757 } else {
758 let metadata = arg.interval.slice(self.ptr_size()..self.ptr_size() * 2);
759 let (size, _) = self.size_align_of_unsized(ty, metadata, locals)?;
760 destination.write_from_bytes(self, &size.to_le_bytes())
761 }
762 }
763 "align_of_val" => {
764 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
765 return Err(MirEvalError::InternalError(
766 "align_of_val generic arg is not provided".into(),
767 ));
768 };
769 let [arg] = args else {
770 return Err(MirEvalError::InternalError(
771 "align_of_val args are not provided".into(),
772 ));
773 };
774 if let Some((_, align)) = self.size_align_of(ty, locals)? {
775 destination.write_from_bytes(self, &align.to_le_bytes())
776 } else {
777 let metadata = arg.interval.slice(self.ptr_size()..self.ptr_size() * 2);
778 let (_, align) = self.size_align_of_unsized(ty, metadata, locals)?;
779 destination.write_from_bytes(self, &align.to_le_bytes())
780 }
781 }
782 "type_name" => {
783 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
784 return Err(MirEvalError::InternalError(
785 "type_name generic arg is not provided".into(),
786 ));
787 };
788 let ty_name = self.db.type_name(ty, locals.body.owner.module(self.db));
789 let len = ty_name.len();
790 let addr = self.heap_allocate(len, 1)?;
791 self.write_memory(addr, ty_name.as_bytes())?;
792 destination.slice(0..self.ptr_size()).write_from_bytes(self, &addr.to_bytes())?;
793 destination
794 .slice(self.ptr_size()..2 * self.ptr_size())
795 .write_from_bytes(self, &len.to_le_bytes())
796 }
797 "needs_drop" => {
798 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
799 return Err(MirEvalError::InternalError(
800 "size_of generic arg is not provided".into(),
801 ));
802 };
803 let result = match has_drop_glue(&self.infcx, ty, self.param_env.param_env) {
804 DropGlue::HasDropGlue => true,
805 DropGlue::None => false,
806 DropGlue::DependOnParams => {
807 never!("should be fully monomorphized now");
808 true
809 }
810 };
811 destination.write_from_bytes(self, &[u8::from(result)])
812 }
813 "ptr_guaranteed_cmp" => {
814 let [lhs, rhs] = args else {
817 return Err(MirEvalError::InternalError(
818 "ptr_guaranteed_cmp args are not provided".into(),
819 ));
820 };
821 let ans = lhs.get(self)? == rhs.get(self)?;
822 destination.write_from_bytes(self, &[u8::from(ans)])
823 }
824 "saturating_add" | "saturating_sub" => {
825 let [lhs, rhs] = args else {
826 return Err(MirEvalError::InternalError(
827 "saturating_add args are not provided".into(),
828 ));
829 };
830 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
831 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
832 let ans = match name {
833 "saturating_add" => lhs.saturating_add(rhs),
834 "saturating_sub" => lhs.saturating_sub(rhs),
835 _ => unreachable!(),
836 };
837 let bits = destination.size * 8;
838 let is_signed = false;
840 let mx: u128 = if is_signed { (1 << (bits - 1)) - 1 } else { (1 << bits) - 1 };
841 let mn: u128 = 0;
843 let ans = cmp::min(mx, cmp::max(mn, ans));
844 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
845 }
846 "wrapping_add" | "unchecked_add" => {
847 let [lhs, rhs] = args else {
848 return Err(MirEvalError::InternalError(
849 "wrapping_add args are not provided".into(),
850 ));
851 };
852 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
853 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
854 let ans = lhs.wrapping_add(rhs);
855 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
856 }
857 "ptr_offset_from_unsigned" | "ptr_offset_from" => {
858 let [lhs, rhs] = args else {
859 return Err(MirEvalError::InternalError(
860 "wrapping_sub args are not provided".into(),
861 ));
862 };
863 let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
864 let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
865 let ans = lhs.wrapping_sub(rhs);
866 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
867 return Err(MirEvalError::InternalError(
868 "ptr_offset_from generic arg is not provided".into(),
869 ));
870 };
871 let size = self.size_of_sized(ty, locals, "ptr_offset_from arg")? as i128;
872 let ans = ans / size;
873 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
874 }
875 "wrapping_sub" | "unchecked_sub" => {
876 let [lhs, rhs] = args else {
877 return Err(MirEvalError::InternalError(
878 "wrapping_sub args are not provided".into(),
879 ));
880 };
881 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
882 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
883 let ans = lhs.wrapping_sub(rhs);
884 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
885 }
886 "wrapping_mul" | "unchecked_mul" => {
887 let [lhs, rhs] = args else {
888 return Err(MirEvalError::InternalError(
889 "wrapping_mul args are not provided".into(),
890 ));
891 };
892 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
893 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
894 let ans = lhs.wrapping_mul(rhs);
895 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
896 }
897 "wrapping_shl" | "unchecked_shl" => {
898 let [lhs, rhs] = args else {
900 return Err(MirEvalError::InternalError(
901 "unchecked_shl args are not provided".into(),
902 ));
903 };
904 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
905 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
906 let ans = lhs.wrapping_shl(rhs as u32);
907 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
908 }
909 "wrapping_shr" | "unchecked_shr" => {
910 let [lhs, rhs] = args else {
912 return Err(MirEvalError::InternalError(
913 "unchecked_shr args are not provided".into(),
914 ));
915 };
916 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
917 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
918 let ans = lhs.wrapping_shr(rhs as u32);
919 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
920 }
921 "unchecked_rem" => {
922 let [lhs, rhs] = args else {
924 return Err(MirEvalError::InternalError(
925 "unchecked_rem args are not provided".into(),
926 ));
927 };
928 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
929 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
930 let ans = lhs.checked_rem(rhs).ok_or_else(|| {
931 MirEvalError::UndefinedBehavior("unchecked_rem with bad inputs".to_owned())
932 })?;
933 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
934 }
935 "unchecked_div" | "exact_div" => {
936 let [lhs, rhs] = args else {
938 return Err(MirEvalError::InternalError(
939 "unchecked_div args are not provided".into(),
940 ));
941 };
942 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
943 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
944 let ans = lhs.checked_div(rhs).ok_or_else(|| {
945 MirEvalError::UndefinedBehavior("unchecked_rem with bad inputs".to_owned())
946 })?;
947 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
948 }
949 "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
950 let [lhs, rhs] = args else {
951 return Err(MirEvalError::InternalError(
952 "const_eval_select args are not provided".into(),
953 ));
954 };
955 let result_ty = Ty::new_tup_from_iter(
956 self.interner(),
957 [lhs.ty, Ty::new_bool(self.interner())].into_iter(),
958 );
959 let op_size = self.size_of_sized(lhs.ty, locals, "operand of add_with_overflow")?;
960 let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, IsSigned::No));
961 let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, IsSigned::No));
962 let (ans, u128overflow) = match name {
963 "add_with_overflow" => lhs.overflowing_add(rhs),
964 "sub_with_overflow" => lhs.overflowing_sub(rhs),
965 "mul_with_overflow" => lhs.overflowing_mul(rhs),
966 _ => unreachable!(),
967 };
968 let is_overflow = u128overflow
969 || ans.to_le_bytes()[op_size..].iter().any(|&it| it != 0 && it != 255);
970 let is_overflow = vec![u8::from(is_overflow)];
971 let layout = self.layout(result_ty)?;
972 let result = self.construct_with_layout(
973 layout.size.bytes_usize(),
974 &layout,
975 None,
976 [ans.to_le_bytes()[0..op_size].to_vec(), is_overflow]
977 .into_iter()
978 .map(IntervalOrOwned::Owned),
979 )?;
980 destination.write_from_bytes(self, &result)
981 }
982 "copy" | "copy_nonoverlapping" => {
983 let [src, dst, offset] = args else {
984 return Err(MirEvalError::InternalError(
985 "copy_nonoverlapping args are not provided".into(),
986 ));
987 };
988 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
989 return Err(MirEvalError::InternalError(
990 "copy_nonoverlapping generic arg is not provided".into(),
991 ));
992 };
993 let src = Address::from_bytes(src.get(self)?)?;
994 let dst = Address::from_bytes(dst.get(self)?)?;
995 let offset = from_bytes!(usize, offset.get(self)?);
996 let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?;
997 let size = offset * size;
998 let src = Interval { addr: src, size };
999 let dst = Interval { addr: dst, size };
1000 dst.write_from_interval(self, src)
1001 }
1002 "slice_get_unchecked" => {
1003 let [slice_ptr, index] = args else {
1004 return Err(MirEvalError::InternalError(
1005 "slice_get_unchecked args are not provided".into(),
1006 ));
1007 };
1008 let Some(ty) = generic_args.as_slice().get(2).and_then(|it| it.ty()) else {
1009 return Err(MirEvalError::InternalError(
1010 "slice_get_unchecked item type is not provided".into(),
1011 ));
1012 };
1013 let slice_ptr = slice_ptr.get(self)?;
1014 let ptr_size = self.ptr_size();
1015 let Some(data) = slice_ptr.get(..ptr_size) else {
1016 return Err(MirEvalError::InternalError(
1017 "slice_get_unchecked slice pointer is too small".into(),
1018 ));
1019 };
1020 let Some(len) = slice_ptr.get(ptr_size..2 * ptr_size) else {
1021 return Err(MirEvalError::InternalError(
1022 "slice_get_unchecked slice metadata is missing".into(),
1023 ));
1024 };
1025 let slice_ptr = Address::from_bytes(data)?;
1026 let len = from_bytes!(usize, len);
1027 let index = from_bytes!(usize, index.get(self)?);
1028 if index >= len {
1029 return Err(MirEvalError::UndefinedBehavior(format!(
1030 "slice_get_unchecked index {index} is out of bounds for slice of length {len}"
1031 )));
1032 }
1033 let size = self.size_of_sized(ty, locals, "slice_get_unchecked item type")?;
1034 let offset = index* size;
1035 let addr = slice_ptr.to_usize() + offset;
1036 let addr = Address::from_usize(addr);
1037 destination.write_from_bytes(self, &addr.to_bytes()[..destination.size])
1038 }
1039 "offset" | "arith_offset" => {
1040 let [ptr, offset] = args else {
1041 return Err(MirEvalError::InternalError("offset args are not provided".into()));
1042 };
1043 let ty = if name == "offset" {
1044 let Some(ty0) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
1045 return Err(MirEvalError::InternalError(
1046 "offset generic arg is not provided".into(),
1047 ));
1048 };
1049 let Some(ty1) = generic_args.as_slice().get(1).and_then(|it| it.ty()) else {
1050 return Err(MirEvalError::InternalError(
1051 "offset generic arg is not provided".into(),
1052 ));
1053 };
1054 if !matches!(
1055 ty1.kind(),
1056 TyKind::Int(rustc_type_ir::IntTy::Isize)
1057 | TyKind::Uint(rustc_type_ir::UintTy::Usize)
1058 ) {
1059 return Err(MirEvalError::InternalError(
1060 "offset generic arg is not usize or isize".into(),
1061 ));
1062 }
1063 match ty0.kind() {
1064 TyKind::RawPtr(ty, _) => ty,
1065 _ => {
1066 return Err(MirEvalError::InternalError(
1067 "offset generic arg is not a raw pointer".into(),
1068 ));
1069 }
1070 }
1071 } else {
1072 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
1073 return Err(MirEvalError::InternalError(
1074 "arith_offset generic arg is not provided".into(),
1075 ));
1076 };
1077 ty
1078 };
1079 let ptr = u128::from_le_bytes(pad16(ptr.get(self)?, IsSigned::No));
1080 let offset = u128::from_le_bytes(pad16(offset.get(self)?, IsSigned::No));
1081 let size = self.size_of_sized(ty, locals, "offset ptr type")? as u128;
1082 let ans = ptr + offset * size;
1083 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
1084 }
1085 "assert_inhabited"
1086 | "assert_zero_valid"
1087 | "assert_uninit_valid"
1088 | "assert_mem_uninitialized_valid" => {
1089 Ok(())
1091 }
1092 "forget" => {
1093 Ok(())
1095 }
1096 "transmute" | "transmute_unchecked" => {
1097 let [arg] = args else {
1098 return Err(MirEvalError::InternalError(
1099 "transmute arg is not provided".into(),
1100 ));
1101 };
1102 destination.write_from_interval(self, arg.interval)
1103 }
1104 "ctpop" => {
1105 let [arg] = args else {
1106 return Err(MirEvalError::InternalError("ctpop arg is not provided".into()));
1107 };
1108 let result = u128::from_le_bytes(pad16(arg.get(self)?, IsSigned::No)).count_ones();
1109 destination
1110 .write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
1111 }
1112 "ctlz" | "ctlz_nonzero" => {
1113 let [arg] = args else {
1114 return Err(MirEvalError::InternalError("ctlz arg is not provided".into()));
1115 };
1116 let result =
1117 u128::from_le_bytes(pad16(arg.get(self)?, IsSigned::No)).leading_zeros() as usize;
1118 let result = result - (128 - arg.interval.size * 8);
1119 destination
1120 .write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
1121 }
1122 "cttz" | "cttz_nonzero" => {
1123 let [arg] = args else {
1124 return Err(MirEvalError::InternalError("cttz arg is not provided".into()));
1125 };
1126 let arg: &[u8] = arg.get(self)?;
1127 let bit_count = arg.len() as u32 * 8;
1128 let result = u128::from_le_bytes(pad16(arg, IsSigned::No)).trailing_zeros().min(bit_count);
1129 destination
1130 .write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
1131 }
1132 "rotate_left" => {
1133 let [lhs, rhs] = args else {
1134 return Err(MirEvalError::InternalError(
1135 "rotate_left args are not provided".into(),
1136 ));
1137 };
1138 let lhs = &lhs.get(self)?[0..destination.size];
1139 let rhs = rhs.get(self)?[0] as u32;
1140 match destination.size {
1141 1 => {
1142 let r = from_bytes!(u8, lhs).rotate_left(rhs);
1143 destination.write_from_bytes(self, &r.to_le_bytes())
1144 }
1145 2 => {
1146 let r = from_bytes!(u16, lhs).rotate_left(rhs);
1147 destination.write_from_bytes(self, &r.to_le_bytes())
1148 }
1149 4 => {
1150 let r = from_bytes!(u32, lhs).rotate_left(rhs);
1151 destination.write_from_bytes(self, &r.to_le_bytes())
1152 }
1153 8 => {
1154 let r = from_bytes!(u64, lhs).rotate_left(rhs);
1155 destination.write_from_bytes(self, &r.to_le_bytes())
1156 }
1157 16 => {
1158 let r = from_bytes!(u128, lhs).rotate_left(rhs);
1159 destination.write_from_bytes(self, &r.to_le_bytes())
1160 }
1161 s => not_supported!("destination with size {s} for rotate_left"),
1162 }
1163 }
1164 "rotate_right" => {
1165 let [lhs, rhs] = args else {
1166 return Err(MirEvalError::InternalError(
1167 "rotate_right args are not provided".into(),
1168 ));
1169 };
1170 let lhs = &lhs.get(self)?[0..destination.size];
1171 let rhs = rhs.get(self)?[0] as u32;
1172 match destination.size {
1173 1 => {
1174 let r = from_bytes!(u8, lhs).rotate_right(rhs);
1175 destination.write_from_bytes(self, &r.to_le_bytes())
1176 }
1177 2 => {
1178 let r = from_bytes!(u16, lhs).rotate_right(rhs);
1179 destination.write_from_bytes(self, &r.to_le_bytes())
1180 }
1181 4 => {
1182 let r = from_bytes!(u32, lhs).rotate_right(rhs);
1183 destination.write_from_bytes(self, &r.to_le_bytes())
1184 }
1185 8 => {
1186 let r = from_bytes!(u64, lhs).rotate_right(rhs);
1187 destination.write_from_bytes(self, &r.to_le_bytes())
1188 }
1189 16 => {
1190 let r = from_bytes!(u128, lhs).rotate_right(rhs);
1191 destination.write_from_bytes(self, &r.to_le_bytes())
1192 }
1193 s => not_supported!("destination with size {s} for rotate_right"),
1194 }
1195 }
1196 "discriminant_value" => {
1197 let [arg] = args else {
1198 return Err(MirEvalError::InternalError(
1199 "discriminant_value arg is not provided".into(),
1200 ));
1201 };
1202 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
1203 return Err(MirEvalError::InternalError(
1204 "discriminant_value generic arg is not provided".into(),
1205 ));
1206 };
1207 let addr = Address::from_bytes(arg.get(self)?)?;
1208 let size = self.size_of_sized(ty, locals, "discriminant_value ptr type")?;
1209 let interval = Interval { addr, size };
1210 let r = self.compute_discriminant(ty, interval.get(self)?)?;
1211 destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])
1212 }
1213 "const_eval_select" => {
1214 let [tuple, const_fn, _] = args else {
1215 return Err(MirEvalError::InternalError(
1216 "const_eval_select args are not provided".into(),
1217 ));
1218 };
1219 let mut args = vec![const_fn.clone()];
1220 let TyKind::Tuple(fields) = tuple.ty.kind() else {
1221 return Err(MirEvalError::InternalError(
1222 "const_eval_select arg[0] is not a tuple".into(),
1223 ));
1224 };
1225 let layout = self.layout(tuple.ty)?;
1226 for (i, field) in fields.iter().enumerate() {
1227 let offset = layout.fields.offset(i).bytes_usize();
1228 let addr = tuple.interval.addr.offset(offset);
1229 args.push(IntervalAndTy::new(addr, field, self, locals)?);
1230 }
1231 if let Some(def) = self.lang_items().FnOnce_call_once {
1232 self.exec_fn_trait(
1233 def,
1234 &args,
1235 GenericArgs::empty(),
1237 locals,
1238 destination,
1239 None,
1240 span,
1241 )?;
1242 return Ok(true);
1243 }
1244 not_supported!("FnOnce was not available for executing const_eval_select");
1245 }
1246 "read_via_copy" | "volatile_load" => {
1247 let [arg] = args else {
1248 return Err(MirEvalError::InternalError(
1249 "read_via_copy args are not provided".into(),
1250 ));
1251 };
1252 let addr = Address::from_bytes(arg.interval.get(self)?)?;
1253 destination.write_from_interval(self, Interval { addr, size: destination.size })
1254 }
1255 "write_via_move" => {
1256 let [ptr, val] = args else {
1257 return Err(MirEvalError::InternalError(
1258 "write_via_move args are not provided".into(),
1259 ));
1260 };
1261 let dst = Address::from_bytes(ptr.get(self)?)?;
1262 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
1263 return Err(MirEvalError::InternalError(
1264 "write_via_copy generic arg is not provided".into(),
1265 ));
1266 };
1267 let size = self.size_of_sized(ty, locals, "write_via_move ptr type")?;
1268 Interval { addr: dst, size }.write_from_interval(self, val.interval)?;
1269 Ok(())
1270 }
1271 "write_bytes" => {
1272 let [dst, val, count] = args else {
1273 return Err(MirEvalError::InternalError(
1274 "write_bytes args are not provided".into(),
1275 ));
1276 };
1277 let count = from_bytes!(usize, count.get(self)?);
1278 let val = from_bytes!(u8, val.get(self)?);
1279 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
1280 return Err(MirEvalError::InternalError(
1281 "write_bytes generic arg is not provided".into(),
1282 ));
1283 };
1284 let dst = Address::from_bytes(dst.get(self)?)?;
1285 let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?;
1286 let size = count * size;
1287 self.write_memory_using_ref(dst, size)?.fill(val);
1288 Ok(())
1289 }
1290 "ptr_metadata" => {
1291 let [ptr] = args else {
1292 return Err(MirEvalError::InternalError(
1293 "ptr_metadata args are not provided".into(),
1294 ));
1295 };
1296 let arg = ptr.interval.get(self)?.to_owned();
1297 let metadata = &arg[self.ptr_size()..];
1298 destination.write_from_bytes(self, metadata)?;
1299 Ok(())
1300 }
1301 "three_way_compare" => {
1302 let [lhs, rhs] = args else {
1303 return Err(MirEvalError::InternalError(
1304 "three_way_compare args are not provided".into(),
1305 ));
1306 };
1307 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
1308 return Err(MirEvalError::InternalError(
1309 "three_way_compare generic arg is not provided".into(),
1310 ));
1311 };
1312 let signed = match ty.kind() {
1313 TyKind::Int(_) => true,
1314 TyKind::Uint(_) => false,
1315 _ => {
1316 return Err(MirEvalError::InternalError(
1317 "three_way_compare expects an integral type".into(),
1318 ));
1319 }
1320 };
1321 let rhs = rhs.get(self)?;
1322 let lhs = lhs.get(self)?;
1323 let mut result = Ordering::Equal;
1324 for (l, r) in lhs.iter().zip(rhs).rev() {
1325 let it = l.cmp(r);
1326 if it != Ordering::Equal {
1327 result = it;
1328 break;
1329 }
1330 }
1331 if signed
1332 && let Some((&l, &r)) = lhs.iter().zip(rhs).next_back()
1333 && l != r
1334 {
1335 result = (l as i8).cmp(&(r as i8));
1336 }
1337 if let Some(e) = self.lang_items().Ordering {
1338 let ty = self.db.ty(e.into()).skip_binder();
1339 let r = self.compute_discriminant(ty, &[result as i8 as u8])?;
1340 destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?;
1341 Ok(())
1342 } else {
1343 Err(MirEvalError::InternalError("Ordering enum not found".into()))
1344 }
1345 }
1346 "aggregate_raw_ptr" => {
1347 let [data, meta] = args else {
1348 return Err(MirEvalError::InternalError(
1349 "aggregate_raw_ptr args are not provided".into(),
1350 ));
1351 };
1352 destination.write_from_interval(self, data.interval)?;
1353 Interval {
1354 addr: destination.addr.offset(data.interval.size),
1355 size: destination.size - data.interval.size,
1356 }
1357 .write_from_interval(self, meta.interval)?;
1358 Ok(())
1359 }
1360 "fabs" => {
1361 let [arg] = args else {
1362 return Err(MirEvalError::InternalError(
1363 "fabs intrinsic signature doesn't match fn (T) -> T".into(),
1364 ));
1365 };
1366 let mut bytes = arg.get(self)?.to_vec();
1367 if let Some(sign_byte) = bytes.last_mut() {
1368 *sign_byte &= 0x7f;
1369 }
1370 destination.write_from_bytes(self, &bytes)
1371 }
1372 "unreachable" => {
1373 return Err(MirEvalError::UndefinedBehavior(
1374 "`unreachable` intrinsic executed".to_owned(),
1375 ));
1376 }
1377 "const_allocate" => {
1378 let [size, align] = args else {
1379 return Err(MirEvalError::InternalError(
1380 "const_allocate args are not provided".into(),
1381 ));
1382 };
1383 let size = from_bytes!(usize, size.get(self)?);
1384 let align = from_bytes!(usize, align.get(self)?);
1385 let result = self.heap_allocate(size, align)?;
1386 destination.write_from_bytes(self, &result.to_bytes())
1387 }
1388 "const_deallocate" => Ok(()),
1389 "caller_location" => {
1390 let Some(location_adt) = self.lang_items().PanicLocation else {
1391 not_supported!("`caller_location` requires the `panic_location` lang item");
1392 };
1393 let location_ty = self.db.ty(location_adt.into()).skip_binder();
1394 let TyKind::Adt(_, subst) = location_ty.kind() else {
1395 return Err(MirEvalError::InternalError(
1396 "`panic_location` lang item is not an ADT".into(),
1397 ));
1398 };
1399 let layout = self.layout(location_ty)?;
1400 let (file, line, col) = self.caller_location_fields(locals.body.owner, span);
1401 let file_len = file.len();
1402 let file_addr = self.heap_allocate(file_len + 1, 1)?;
1403 self.write_memory(file_addr, file.as_bytes())?;
1404 let ptr_size = self.ptr_size();
1405 let field_types = self.db.field_types(location_adt.into());
1406 let mut line_col = [line, col].into_iter();
1407 let mut fields = Vec::with_capacity(field_types.iter().count());
1408 for (_, field) in field_types.iter() {
1409 let field_ty = field.ty().instantiate(self.interner(), subst).skip_norm_wip();
1410 let bytes =
1411 if matches!(field_ty.kind(), TyKind::Uint(rustc_type_ir::UintTy::U32)) {
1412 line_col.next().unwrap_or(0).to_le_bytes().to_vec()
1413 } else {
1414 let size =
1415 self.size_of_sized(field_ty, locals, "caller_location field")?;
1416 if size == ptr_size * 2 {
1417 let mut bytes = file_addr.to_bytes()[..ptr_size].to_vec();
1419 bytes.extend_from_slice(&file_len.to_le_bytes()[..ptr_size]);
1420 bytes
1421 } else {
1422 vec![0; size]
1423 }
1424 };
1425 fields.push(IntervalOrOwned::Owned(bytes));
1426 }
1427 let location = self.construct_with_layout(
1428 layout.size.bytes_usize(),
1429 &layout,
1430 None,
1431 fields.into_iter(),
1432 )?;
1433 let location_addr =
1434 self.heap_allocate(layout.size.bytes_usize(), layout.align.bytes() as usize)?;
1435 self.write_memory(location_addr, &location)?;
1436 destination.write_from_bytes(self, &location_addr.to_bytes()[..ptr_size])
1437 }
1438 "box_new" => {
1439 let ty = generic_args.type_at(0);
1440 let Some((size, align)) = self.size_align_of(ty, locals)? else {
1441 not_supported!("unsized box initialization");
1442 };
1443 let addr = self.heap_allocate(size, align)?;
1444 self.copy_from_interval(addr, args[0].interval)?;
1445 destination.write_from_bytes(self, &addr.to_bytes()[..self.ptr_size()])
1446 }
1447 _ if needs_override => not_supported!("intrinsic {name} is not implemented"),
1448 _ => return Ok(false),
1449 }
1450 .map(|()| true)
1451 }
1452
1453 fn size_align_of_unsized(
1454 &mut self,
1455 ty: Ty<'db>,
1456 metadata: Interval,
1457 locals: &Locals<'a, 'db>,
1458 ) -> Result<'db, (usize, usize)> {
1459 Ok(match ty.kind() {
1460 TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1),
1461 TyKind::Slice(inner) => {
1462 let len = from_bytes!(usize, metadata.get(self)?);
1463 let (size, align) = self.size_align_of_sized(inner, locals, "slice inner type")?;
1464 (size * len, align)
1465 }
1466 TyKind::Dynamic(..) => self.size_align_of_sized(
1467 self.vtable_map.ty_of_bytes(metadata.get(self)?)?,
1468 locals,
1469 "dyn concrete type",
1470 )?,
1471 TyKind::Adt(adt_def, subst) => {
1472 let id = adt_def.def_id();
1473 let layout = self.layout_adt(id, subst)?;
1474 let id = match id {
1475 AdtId::StructId(s) => s,
1476 _ => not_supported!("unsized enum or union"),
1477 };
1478 let field_types = self.db.field_types(id.into());
1479 let last_field_ty = field_types
1480 .iter()
1481 .next_back()
1482 .unwrap()
1483 .1
1484 .ty()
1485 .instantiate(self.interner(), subst)
1486 .skip_norm_wip();
1487 let sized_part_size =
1488 layout.fields.offset(field_types.iter().count() - 1).bytes_usize();
1489 let sized_part_align = layout.align.bytes() as usize;
1490 let (unsized_part_size, unsized_part_align) =
1491 self.size_align_of_unsized(last_field_ty, metadata, locals)?;
1492 let align = sized_part_align.max(unsized_part_align) as isize;
1493 let size = (sized_part_size + unsized_part_size) as isize;
1494 let size = (size + (align - 1)) & (-align);
1505 (size as usize, align as usize)
1506 }
1507 _ => not_supported!("unsized type other than str, slice, struct and dyn"),
1508 })
1509 }
1510
1511 fn exec_atomic_intrinsic(
1512 &mut self,
1513 name: &str,
1514 args: &[IntervalAndTy<'db>],
1515 generic_args: GenericArgs<'db>,
1516 destination: Interval,
1517 locals: &Locals<'a, 'db>,
1518 _span: MirSpan,
1519 ) -> Result<'db, ()> {
1520 if name.starts_with("singlethreadfence_") || name.starts_with("fence_") {
1524 return Ok(());
1525 }
1526
1527 let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
1530 return Err(MirEvalError::InternalError(
1531 "atomic intrinsic generic arg is not provided".into(),
1532 ));
1533 };
1534 let Some(arg0) = args.first() else {
1535 return Err(MirEvalError::InternalError(
1536 "atomic intrinsic arg0 is not provided".into(),
1537 ));
1538 };
1539 let arg0_addr = Address::from_bytes(arg0.get(self)?)?;
1540 let arg0_interval =
1541 Interval::new(arg0_addr, self.size_of_sized(ty, locals, "atomic intrinsic type arg")?);
1542 if name.starts_with("load_") {
1543 return destination.write_from_interval(self, arg0_interval);
1544 }
1545 let Some(arg1) = args.get(1) else {
1546 return Err(MirEvalError::InternalError(
1547 "atomic intrinsic arg1 is not provided".into(),
1548 ));
1549 };
1550 if name.starts_with("store_") {
1551 return arg0_interval.write_from_interval(self, arg1.interval);
1552 }
1553 if name.starts_with("xchg_") {
1554 destination.write_from_interval(self, arg0_interval)?;
1555 return arg0_interval.write_from_interval(self, arg1.interval);
1556 }
1557 if name.starts_with("xadd_") {
1558 destination.write_from_interval(self, arg0_interval)?;
1559 let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, IsSigned::No));
1560 let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, IsSigned::No));
1561 let ans = lhs.wrapping_add(rhs);
1562 return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]);
1563 }
1564 if name.starts_with("xsub_") {
1565 destination.write_from_interval(self, arg0_interval)?;
1566 let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, IsSigned::No));
1567 let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, IsSigned::No));
1568 let ans = lhs.wrapping_sub(rhs);
1569 return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]);
1570 }
1571 if name.starts_with("and_") {
1572 destination.write_from_interval(self, arg0_interval)?;
1573 let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, IsSigned::No));
1574 let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, IsSigned::No));
1575 let ans = lhs & rhs;
1576 return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]);
1577 }
1578 if name.starts_with("or_") {
1579 destination.write_from_interval(self, arg0_interval)?;
1580 let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, IsSigned::No));
1581 let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, IsSigned::No));
1582 let ans = lhs | rhs;
1583 return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]);
1584 }
1585 if name.starts_with("xor_") {
1586 destination.write_from_interval(self, arg0_interval)?;
1587 let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, IsSigned::No));
1588 let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, IsSigned::No));
1589 let ans = lhs ^ rhs;
1590 return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]);
1591 }
1592 if name.starts_with("nand_") {
1593 destination.write_from_interval(self, arg0_interval)?;
1594 let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, IsSigned::No));
1595 let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, IsSigned::No));
1596 let ans = !(lhs & rhs);
1597 return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]);
1598 }
1599 let Some(arg2) = args.get(2) else {
1600 return Err(MirEvalError::InternalError(
1601 "atomic intrinsic arg2 is not provided".into(),
1602 ));
1603 };
1604 if name.starts_with("cxchg_") || name.starts_with("cxchgweak_") {
1605 let dest = if arg1.get(self)? == arg0_interval.get(self)? {
1606 arg0_interval.write_from_interval(self, arg2.interval)?;
1607 (arg1.interval, true)
1608 } else {
1609 (arg0_interval, false)
1610 };
1611 let result_ty = Ty::new_tup_from_iter(
1612 self.interner(),
1613 [ty, Ty::new_bool(self.interner())].into_iter(),
1614 );
1615 let layout = self.layout(result_ty)?;
1616 let result = self.construct_with_layout(
1617 layout.size.bytes_usize(),
1618 &layout,
1619 None,
1620 [IntervalOrOwned::Borrowed(dest.0), IntervalOrOwned::Owned(vec![u8::from(dest.1)])]
1621 .into_iter(),
1622 )?;
1623 return destination.write_from_bytes(self, &result);
1624 }
1625 not_supported!("unknown atomic intrinsic {name}");
1626 }
1627}