1use rustc_middle::ty;
2use rustc_middle::ty::FloatTy;
3
4use super::check_intrinsic_arg_count;
5use crate::helpers::{ToHost, ToSoft};
6use crate::*;
7
8impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
9pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10 fn emulate_simd_intrinsic(
13 &mut self,
14 intrinsic_name: &str,
15 args: &[OpTy<'tcx>],
16 dest: &MPlaceTy<'tcx>,
17 ) -> InterpResult<'tcx, EmulateItemResult> {
18 let this = self.eval_context_mut();
19 match intrinsic_name {
20 #[rustfmt::skip]
21 | "fsqrt"
22 | "fsin"
23 | "fcos"
24 | "fexp"
25 | "fexp2"
26 | "flog"
27 | "flog2"
28 | "flog10"
29 => {
30 let [op] = check_intrinsic_arg_count(args)?;
31 let (op, op_len) = this.project_to_simd(op)?;
32 let (dest, dest_len) = this.project_to_simd(dest)?;
33
34 assert_eq!(dest_len, op_len);
35
36 for i in 0..dest_len {
37 let op = this.read_immediate(&this.project_index(&op, i)?)?;
38 let dest = this.project_index(&dest, i)?;
39 let ty::Float(float_ty) = op.layout.ty.kind() else {
40 span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
41 };
42 let val = match float_ty {
45 FloatTy::F16 => unimplemented!("f16_f128"),
46 FloatTy::F32 => {
47 let f = op.to_scalar().to_f32()?;
48 let res = match intrinsic_name {
49 "fsqrt" => math::sqrt(f),
50 "fsin" => f.to_host().sin().to_soft(),
51 "fcos" => f.to_host().cos().to_soft(),
52 "fexp" => f.to_host().exp().to_soft(),
53 "fexp2" => f.to_host().exp2().to_soft(),
54 "flog" => f.to_host().ln().to_soft(),
55 "flog2" => f.to_host().log2().to_soft(),
56 "flog10" => f.to_host().log10().to_soft(),
57 _ => bug!(),
58 };
59 let res = this.adjust_nan(res, &[f]);
60 Scalar::from(res)
61 }
62 FloatTy::F64 => {
63 let f = op.to_scalar().to_f64()?;
64 let res = match intrinsic_name {
65 "fsqrt" => math::sqrt(f),
66 "fsin" => f.to_host().sin().to_soft(),
67 "fcos" => f.to_host().cos().to_soft(),
68 "fexp" => f.to_host().exp().to_soft(),
69 "fexp2" => f.to_host().exp2().to_soft(),
70 "flog" => f.to_host().ln().to_soft(),
71 "flog2" => f.to_host().log2().to_soft(),
72 "flog10" => f.to_host().log10().to_soft(),
73 _ => bug!(),
74 };
75 let res = this.adjust_nan(res, &[f]);
76 Scalar::from(res)
77 }
78 FloatTy::F128 => unimplemented!("f16_f128"),
79 };
80
81 this.write_scalar(val, &dest)?;
82 }
83 }
84 "expose_provenance" => {
85 let [op] = check_intrinsic_arg_count(args)?;
86 let (op, op_len) = this.project_to_simd(op)?;
87 let (dest, dest_len) = this.project_to_simd(dest)?;
88
89 assert_eq!(dest_len, op_len);
90
91 for i in 0..dest_len {
92 let op = this.read_immediate(&this.project_index(&op, i)?)?;
93 let dest = this.project_index(&dest, i)?;
94
95 let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
96 (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) =>
98 this.pointer_expose_provenance_cast(&op, dest.layout)?,
99 _ =>
101 throw_unsup_format!(
102 "Unsupported `simd_expose_provenance` from element type {from_ty} to {to_ty}",
103 from_ty = op.layout.ty,
104 to_ty = dest.layout.ty,
105 ),
106 };
107 this.write_immediate(*val, &dest)?;
108 }
109 }
110
111 _ => return interp_ok(EmulateItemResult::NotSupported),
112 }
113 interp_ok(EmulateItemResult::NeedsReturn)
114 }
115}