1use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS};
2use rustc_middle::ty;
3use rustc_middle::ty::FloatTy;
4
5use super::check_intrinsic_arg_count;
6use crate::math::{HostUnaryFloatOp, host_unary_float_op};
7use crate::*;
8
9impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
10pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
11 fn emulate_simd_intrinsic(
14 &mut self,
15 intrinsic_name: &str,
16 args: &[OpTy<'tcx>],
17 dest: &MPlaceTy<'tcx>,
18 ) -> InterpResult<'tcx, EmulateItemResult> {
19 let this = self.eval_context_mut();
20 match intrinsic_name {
21 "fsqrt" => {
23 let [op] = check_intrinsic_arg_count(args)?;
24 let (op, op_len) = this.project_to_simd(op)?;
25 let (dest, dest_len) = this.project_to_simd(dest)?;
26
27 assert_eq!(dest_len, op_len);
28
29 for i in 0..dest_len {
30 let op = this.project_index(&op, i)?;
31 let dest = this.project_index(&dest, i)?;
32 let ty::Float(float_ty) = op.layout.ty.kind() else {
33 span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
34 };
35 match float_ty {
36 FloatTy::F16 => math::sqrt_op::<IeeeFloat<HalfS>>(this, &op, &dest)?,
37 FloatTy::F32 => math::sqrt_op::<IeeeFloat<SingleS>>(this, &op, &dest)?,
38 FloatTy::F64 => math::sqrt_op::<IeeeFloat<DoubleS>>(this, &op, &dest)?,
39 FloatTy::F128 => math::sqrt_op::<IeeeFloat<QuadS>>(this, &op, &dest)?,
40 };
41 }
42 }
43
44 "fsin" | "fcos" | "fexp" | "fexp2" | "flog" | "flog2" | "flog10" => {
46 let [op] = check_intrinsic_arg_count(args)?;
47 let (op, op_len) = this.project_to_simd(op)?;
48 let (dest, dest_len) = this.project_to_simd(dest)?;
49
50 assert_eq!(dest_len, op_len);
51
52 let host_op = match intrinsic_name {
53 "fsin" => HostUnaryFloatOp::Sin,
54 "fcos" => HostUnaryFloatOp::Cos,
55 "fexp" => HostUnaryFloatOp::Exp,
56 "fexp2" => HostUnaryFloatOp::Exp2,
57 "flog" => HostUnaryFloatOp::Log,
58 "flog2" => HostUnaryFloatOp::Log2,
59 "flog10" => HostUnaryFloatOp::Log10,
60 _ => bug!(),
61 };
62
63 for i in 0..dest_len {
64 let op = this.project_index(&op, i)?;
65 let dest = this.project_index(&dest, i)?;
66 let ty::Float(float_ty) = op.layout.ty.kind() else {
67 span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
68 };
69 match float_ty {
72 FloatTy::F16 => host_unary_float_op::<HalfS>(this, &op, host_op, &dest)?,
73 FloatTy::F32 => host_unary_float_op::<SingleS>(this, &op, host_op, &dest)?,
74 FloatTy::F64 => host_unary_float_op::<DoubleS>(this, &op, host_op, &dest)?,
75 FloatTy::F128 => unimplemented!("f128"), }
77 }
78 }
79 "expose_provenance" => {
80 let [op] = check_intrinsic_arg_count(args)?;
81 let (op, op_len) = this.project_to_simd(op)?;
82 let (dest, dest_len) = this.project_to_simd(dest)?;
83
84 assert_eq!(dest_len, op_len);
85
86 for i in 0..dest_len {
87 let op = this.read_immediate(&this.project_index(&op, i)?)?;
88 let dest = this.project_index(&dest, i)?;
89
90 let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
91 (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) =>
93 this.pointer_expose_provenance_cast(&op, dest.layout)?,
94 _ =>
96 throw_unsup_format!(
97 "Unsupported `simd_expose_provenance` from element type {from_ty} to {to_ty}",
98 from_ty = op.layout.ty,
99 to_ty = dest.layout.ty,
100 ),
101 };
102 this.write_immediate(*val, &dest)?;
103 }
104 }
105
106 _ => return interp_ok(EmulateItemResult::NotSupported),
107 }
108 interp_ok(EmulateItemResult::NeedsReturn)
109 }
110}