Skip to main content

hir_ty/mir/eval/
shim.rs

1//! Interpret intrinsics, lang items and `extern "C"` wellknown functions which their implementation
2//! is not available.
3//!
4use 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            // Clone has special impls for tuples and function pointers
104            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 early to prevent caching clone as non special fn.
110            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        // `PanicFmt` is redirected to `ConstPanicFmt`
121        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    /// Clone has special impls for tuples and function pointers
131    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) => { /* no-op for now */ }
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            // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
276            return Some(BeginPanic);
277        }
278
279        // We want to execute these functions with special logic
280        // `PanicFmt` is not detected here as it's redirected later.
281        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                // SYS_getrandom
378                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                // return 0 as success
467                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                // return 0 as success
496                destination.write_from_bytes(self, &0u64.to_le_bytes()[0..destination.size])?;
497                Ok(())
498            }
499            "pthread_key_delete" => {
500                // we ignore this currently
501                // return 0 as success
502                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                // Only enable core 0 (we are single threaded anyway), which is bitset 0x0000001
520                self.write_memory(set, &[1])?;
521                // return 0 as success
522                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                        // Write null as fail
546                        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        // FIXME(#17451): Add `f16` and `f128` intrinsics.
582        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                        // FIXME: these rounds should be different, but only `.round()` is stable now.
606                        "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                        // FIXME: these rounds should be different, but only `.round()` is stable now.
678                        "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                    // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to
796                    // render full paths.
797                    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                // FIXME: this is wrong for const eval, it should return 2 in some
828                // cases.
829                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                // FIXME: signed
852                let is_signed = false;
853                let mx: u128 = if is_signed { (1 << (bits - 1)) - 1 } else { (1 << bits) - 1 };
854                // FIXME: signed
855                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                // FIXME: signed
912                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                // FIXME: signed
924                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                // FIXME: signed
936                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                // FIXME: signed
950                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                // FIXME: We should actually implement these checks
1103                Ok(())
1104            }
1105            "forget" => {
1106                // FIXME
1107                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                        // FIXME: wrong for manual impls of `FnOnce`
1249                        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                                // The string slice pointing at the file name: (data pointer, length).
1431                                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                // Must add any necessary padding to `size`
1508                // (to make it a multiple of `align`) before returning it.
1509                //
1510                // Namely, the returned size should be, in C notation:
1511                //
1512                //   `size + ((size & (align-1)) ? align : 0)`
1513                //
1514                // emulated via the semi-standard fast bit trick:
1515                //
1516                //   `(size + (align-1)) & -align`
1517                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        // We are a single threaded runtime with no UB checking and no optimization, so
1534        // we can implement atomic intrinsics as normal functions.
1535
1536        if name.starts_with("singlethreadfence_") || name.starts_with("fence_") {
1537            return Ok(());
1538        }
1539
1540        // The rest of atomic intrinsics have exactly one generic arg
1541
1542        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}