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