1use rustc_abi::CanonAbi;
2use rustc_apfloat::Float;
3use rustc_middle::ty::Ty;
4use rustc_span::Symbol;
5use rustc_target::callconv::FnAbi;
6
7use self::helpers::{ToHost, ToSoft};
8use crate::*;
9
10impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
11pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12 fn emulate_foreign_item_inner(
13 &mut self,
14 link_name: Symbol,
15 abi: &FnAbi<'tcx, Ty<'tcx>>,
16 args: &[OpTy<'tcx>],
17 dest: &MPlaceTy<'tcx>,
18 ) -> InterpResult<'tcx, EmulateItemResult> {
19 let this = self.eval_context_mut();
20
21 match link_name.as_str() {
23 #[rustfmt::skip]
25 | "cbrtf"
26 | "coshf"
27 | "sinhf"
28 | "tanf"
29 | "tanhf"
30 | "acosf"
31 | "asinf"
32 | "atanf"
33 | "log1pf"
34 | "expm1f"
35 | "tgammaf"
36 | "erff"
37 | "erfcf"
38 => {
39 let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
40 let f = this.read_scalar(f)?.to_f32()?;
41
42 let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
43 let f_host = f.to_host();
46 let res = match link_name.as_str() {
47 "cbrtf" => f_host.cbrt(),
48 "coshf" => f_host.cosh(),
49 "sinhf" => f_host.sinh(),
50 "tanf" => f_host.tan(),
51 "tanhf" => f_host.tanh(),
52 "acosf" => f_host.acos(),
53 "asinf" => f_host.asin(),
54 "atanf" => f_host.atan(),
55 "log1pf" => f_host.ln_1p(),
56 "expm1f" => f_host.exp_m1(),
57 "tgammaf" => f_host.gamma(),
58 "erff" => f_host.erf(),
59 "erfcf" => f_host.erfc(),
60 _ => bug!(),
61 };
62 let res = res.to_soft();
63 let res = math::apply_random_float_error_ulp(this, res, 4);
66
67 math::clamp_float_value(link_name.as_str(), res)
70 });
71 let res = this.adjust_nan(res, &[f]);
72 this.write_scalar(res, dest)?;
73 }
74 #[rustfmt::skip]
75 | "_hypotf"
76 | "hypotf"
77 | "atan2f"
78 | "fdimf"
79 => {
80 let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
81 let f1 = this.read_scalar(f1)?.to_f32()?;
82 let f2 = this.read_scalar(f2)?.to_f32()?;
83
84 let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2])
85 .unwrap_or_else(|| {
86 let res = match link_name.as_str() {
87 "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
91 "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
92 #[allow(deprecated)]
93 "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
94 _ => bug!(),
95 };
96 let res = math::apply_random_float_error_ulp(this, res, 4);
99
100 math::clamp_float_value(link_name.as_str(), res)
103 });
104 let res = this.adjust_nan(res, &[f1, f2]);
105 this.write_scalar(res, dest)?;
106 }
107 #[rustfmt::skip]
108 | "cbrt"
109 | "cosh"
110 | "sinh"
111 | "tan"
112 | "tanh"
113 | "acos"
114 | "asin"
115 | "atan"
116 | "log1p"
117 | "expm1"
118 | "tgamma"
119 | "erf"
120 | "erfc"
121 => {
122 let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
123 let f = this.read_scalar(f)?.to_f64()?;
124
125 let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
126 let f_host = f.to_host();
129 let res = match link_name.as_str() {
130 "cbrt" => f_host.cbrt(),
131 "cosh" => f_host.cosh(),
132 "sinh" => f_host.sinh(),
133 "tan" => f_host.tan(),
134 "tanh" => f_host.tanh(),
135 "acos" => f_host.acos(),
136 "asin" => f_host.asin(),
137 "atan" => f_host.atan(),
138 "log1p" => f_host.ln_1p(),
139 "expm1" => f_host.exp_m1(),
140 "tgamma" => f_host.gamma(),
141 "erf" => f_host.erf(),
142 "erfc" => f_host.erfc(),
143 _ => bug!(),
144 };
145 let res = res.to_soft();
146 let res = math::apply_random_float_error_ulp(this, res, 4);
149
150 math::clamp_float_value(link_name.as_str(), res)
153 });
154 let res = this.adjust_nan(res, &[f]);
155 this.write_scalar(res, dest)?;
156 }
157 #[rustfmt::skip]
158 | "_hypot"
159 | "hypot"
160 | "atan2"
161 | "fdim"
162 => {
163 let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
164 let f1 = this.read_scalar(f1)?.to_f64()?;
165 let f2 = this.read_scalar(f2)?.to_f64()?;
166
167 let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| {
168 let res = match link_name.as_str() {
169 "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
173 "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
174 #[allow(deprecated)]
175 "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
176 _ => bug!(),
177 };
178 let res = math::apply_random_float_error_ulp(this, res, 4);
181
182 math::clamp_float_value(link_name.as_str(), res)
185 });
186 let res = this.adjust_nan(res, &[f1, f2]);
187 this.write_scalar(res, dest)?;
188 }
189 #[rustfmt::skip]
190 | "_ldexp"
191 | "ldexp"
192 | "scalbn"
193 => {
194 let [x, exp] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
195 let x = this.read_scalar(x)?.to_f64()?;
197 let exp = this.read_scalar(exp)?.to_i32()?;
198
199 let res = x.scalbn(exp);
200 let res = this.adjust_nan(res, &[x]);
201 this.write_scalar(res, dest)?;
202 }
203 "lgammaf_r" => {
204 let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
205 let x = this.read_scalar(x)?.to_f32()?;
206 let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
207
208 let (res, sign) = x.to_host().ln_gamma();
210 this.write_int(sign, &signp)?;
211
212 let res = res.to_soft();
213 let res = math::apply_random_float_error_ulp(this, res, 4);
216 let res = math::clamp_float_value(link_name.as_str(), res);
219 let res = this.adjust_nan(res, &[x]);
220 this.write_scalar(res, dest)?;
221 }
222 "lgamma_r" => {
223 let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
224 let x = this.read_scalar(x)?.to_f64()?;
225 let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
226
227 let (res, sign) = x.to_host().ln_gamma();
229 this.write_int(sign, &signp)?;
230
231 let res = res.to_soft();
232 let res = math::apply_random_float_error_ulp(this, res, 4);
235 let res = math::clamp_float_value(link_name.as_str(), res);
238 let res = this.adjust_nan(res, &[x]);
239 this.write_scalar(res, dest)?;
240 }
241
242 _ => return interp_ok(EmulateItemResult::NotSupported),
243 }
244
245 interp_ok(EmulateItemResult::NeedsReturn)
246 }
247}