1+ use rustc_apfloat:: ieee:: { DoubleS , HalfS , IeeeFloat , Semantics , SingleS } ;
12use rustc_apfloat:: { self , Float , FloatConvert , Round } ;
23use rustc_middle:: mir;
34use rustc_middle:: ty:: { self , FloatTy } ;
45
5- use self :: helpers:: { ToHost , ToSoft } ;
6- use self :: math:: { HostFloatOperation , IeeeExt } ;
6+ use self :: math:: { HostFloatOperation , HostUnaryFloatOp , IeeeExt , host_unary_float_op} ;
77use super :: check_intrinsic_arg_count;
88use crate :: * ;
99
@@ -13,26 +13,11 @@ fn sqrt<'tcx, F: Float + FloatConvert<F> + Into<Scalar>>(
1313 dest : & MPlaceTy < ' tcx > ,
1414) -> InterpResult < ' tcx > {
1515 let [ f] = check_intrinsic_arg_count ( args) ?;
16- let f = this. read_scalar ( f) ?;
17- let f: F = f. to_float ( ) ?;
18- // Sqrt is specified to be fully precise.
19- let res = math:: sqrt ( f) ;
20- let res = this. adjust_nan ( res, & [ f] ) ;
21- this. write_scalar ( res, dest)
22- }
23-
24- #[ derive( Debug , Clone , Copy ) ]
25- enum HostFloatUnaryOp {
26- Sin ,
27- Cos ,
28- Exp ,
29- Exp2 ,
30- Log ,
31- Log10 ,
32- Log2 ,
16+ math:: sqrt_op :: < F > ( this, f, dest)
3317}
3418
35- fn is_host_unary_float_op ( intrinsic_name : & str ) -> Option < ( FloatTy , HostFloatUnaryOp ) > {
19+ /// Determine which float operation on which type this is.
20+ fn is_host_unary_float_op ( intrinsic_name : & str ) -> Option < ( FloatTy , HostUnaryFloatOp ) > {
3621 let ( op, ty) = intrinsic_name. rsplit_once ( 'f' ) ?;
3722
3823 let float_ty = match ty {
@@ -44,19 +29,68 @@ fn is_host_unary_float_op(intrinsic_name: &str) -> Option<(FloatTy, HostFloatUna
4429 } ;
4530
4631 let host_float_op = match op {
47- "sin" => HostFloatUnaryOp :: Sin ,
48- "cos" => HostFloatUnaryOp :: Cos ,
49- "exp" => HostFloatUnaryOp :: Exp ,
50- "exp2" => HostFloatUnaryOp :: Exp2 ,
51- "log" => HostFloatUnaryOp :: Log ,
52- "log10" => HostFloatUnaryOp :: Log10 ,
53- "log2" => HostFloatUnaryOp :: Log2 ,
32+ "sin" => HostUnaryFloatOp :: Sin ,
33+ "cos" => HostUnaryFloatOp :: Cos ,
34+ "exp" => HostUnaryFloatOp :: Exp ,
35+ "exp2" => HostUnaryFloatOp :: Exp2 ,
36+ "log" => HostUnaryFloatOp :: Log ,
37+ "log10" => HostUnaryFloatOp :: Log10 ,
38+ "log2" => HostUnaryFloatOp :: Log2 ,
5439 _ => return None ,
5540 } ;
5641
5742 Some ( ( float_ty, host_float_op) )
5843}
5944
45+ fn pow_intrinsic < ' tcx , S : Semantics > (
46+ this : & mut MiriInterpCx < ' tcx > ,
47+ args : & [ OpTy < ' tcx > ] ,
48+ dest : & MPlaceTy < ' tcx > ,
49+ ) -> InterpResult < ' tcx , ( ) >
50+ where
51+ IeeeFloat < S > : HostFloatOperation + IeeeExt + Float + Into < Scalar > ,
52+ {
53+ let [ f1, f2] = check_intrinsic_arg_count ( args) ?;
54+ let f1: IeeeFloat < S > = this. read_scalar ( f1) ?. to_float ( ) ?;
55+ let f2: IeeeFloat < S > = this. read_scalar ( f2) ?. to_float ( ) ?;
56+
57+ let res = math:: fixed_float_value ( this, "pow" , & [ f1, f2] ) . unwrap_or_else ( || {
58+ // Using host floats (but it's fine, this operation does not have guaranteed precision).
59+ let res = f1. host_powf ( f2) ;
60+
61+ // Apply a relative error of 4ULP to introduce some non-determinism
62+ // simulating imprecise implementations and optimizations.
63+ math:: apply_random_float_error_ulp ( this, res, 4 )
64+ } ) ;
65+ let res = this. adjust_nan ( res, & [ f1, f2] ) ;
66+ this. write_scalar ( res, dest) ?;
67+ interp_ok ( ( ) )
68+ }
69+ fn powi_intrinsic < ' tcx , S : Semantics > (
70+ this : & mut MiriInterpCx < ' tcx > ,
71+ args : & [ OpTy < ' tcx > ] ,
72+ dest : & MPlaceTy < ' tcx > ,
73+ ) -> InterpResult < ' tcx , ( ) >
74+ where
75+ IeeeFloat < S > : HostFloatOperation + IeeeExt + Float + Into < Scalar > ,
76+ {
77+ let [ f, i] = check_intrinsic_arg_count ( args) ?;
78+ let f: IeeeFloat < S > = this. read_scalar ( f) ?. to_float ( ) ?;
79+ let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
80+
81+ let res = math:: fixed_powi_value ( this, f, i) . unwrap_or_else ( || {
82+ // Using host floats (but it's fine, this operation does not have guaranteed precision).
83+ let res = f. host_powi ( i) ;
84+
85+ // Apply a relative error of 4ULP to introduce some non-determinism
86+ // simulating imprecise implementations and optimizations.
87+ math:: apply_random_float_error_ulp ( this, res, 4 )
88+ } ) ;
89+ let res = this. adjust_nan ( res, & [ f] ) ;
90+ this. write_scalar ( res, dest) ?;
91+ interp_ok ( ( ) )
92+ }
93+
6094impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
6195pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
6296 fn emulate_math_intrinsic (
@@ -145,167 +179,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
145179 }
146180
147181 // Operations that need host floats.
148- _ if let Some ( ( float_ty, host_float_op) ) = is_host_unary_float_op ( intrinsic_name) => {
149- use rustc_apfloat:: ieee:: { IeeeFloat , Semantics } ;
150-
151- fn eval_host_float_operation < ' tcx , S : Semantics > (
152- this : & mut MiriInterpCx < ' tcx > ,
153- f : IeeeFloat < S > ,
154- intrinsic_name : & str ,
155- host_float_op : HostFloatUnaryOp ,
156- dest : & MPlaceTy < ' tcx > ,
157- ) -> InterpResult < ' tcx , ( ) >
158- where
159- IeeeFloat < S > : HostFloatOperation + IeeeExt + Float ,
160- IeeeFloat < S > : Into < rustc_const_eval:: interpret:: Scalar < machine:: Provenance > > ,
161- {
162- use HostFloatOperation ;
163-
164- let res =
165- math:: fixed_float_value ( this, intrinsic_name, & [ f] ) . unwrap_or_else ( || {
166- // Using host floats (but it's fine, these operations do not have
167- // guaranteed precision).
168- let res = match host_float_op {
169- HostFloatUnaryOp :: Sin => HostFloatOperation :: host_sin ( f) ,
170- HostFloatUnaryOp :: Cos => HostFloatOperation :: host_cos ( f) ,
171- HostFloatUnaryOp :: Exp => HostFloatOperation :: host_exp ( f) ,
172- HostFloatUnaryOp :: Exp2 => HostFloatOperation :: host_exp2 ( f) ,
173- HostFloatUnaryOp :: Log => HostFloatOperation :: host_log ( f) ,
174- HostFloatUnaryOp :: Log10 => HostFloatOperation :: host_log10 ( f) ,
175- HostFloatUnaryOp :: Log2 => HostFloatOperation :: host_log2 ( f) ,
176- } ;
177-
178- // Apply a relative error of 4ULP to introduce some non-determinism
179- // simulating imprecise implementations and optimizations.
180- let res = math:: apply_random_float_error_ulp ( this, res, 4 ) ;
181-
182- // Clamp the result to the guaranteed range of this function according to the C standard,
183- // if any.
184- math:: clamp_float_value ( intrinsic_name, res)
185- } ) ;
186-
187- let res = this. adjust_nan ( res, & [ f] ) ;
188- this. write_scalar ( res, dest)
189- }
190-
182+ _ if let Some ( ( float_ty, op) ) = is_host_unary_float_op ( intrinsic_name) => {
191183 let [ f] = check_intrinsic_arg_count ( args) ?;
192184 match float_ty {
193- FloatTy :: F16 => {
194- let f = this. read_scalar ( f) ?. to_f16 ( ) ?;
195- eval_host_float_operation ( this, f, intrinsic_name, host_float_op, dest) ?;
196- }
197- FloatTy :: F32 => {
198- let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
199- eval_host_float_operation ( this, f, intrinsic_name, host_float_op, dest) ?;
200- }
201- FloatTy :: F64 => {
202- let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
203- eval_host_float_operation ( this, f, intrinsic_name, host_float_op, dest) ?;
204- }
185+ FloatTy :: F16 => host_unary_float_op :: < HalfS > ( this, f, op, dest) ?,
186+ FloatTy :: F32 => host_unary_float_op :: < SingleS > ( this, f, op, dest) ?,
187+ FloatTy :: F64 => host_unary_float_op :: < DoubleS > ( this, f, op, dest) ?,
205188 FloatTy :: F128 => todo ! ( "f128" ) , // FIXME(f128)
206189 } ;
207190 }
208191
209- "powf16" => {
210- let [ f1, f2] = check_intrinsic_arg_count ( args) ?;
211- let f1 = this. read_scalar ( f1) ?. to_f16 ( ) ?;
212- let f2 = this. read_scalar ( f2) ?. to_f16 ( ) ?;
213-
214- let res =
215- math:: fixed_float_value ( this, intrinsic_name, & [ f1, f2] ) . unwrap_or_else ( || {
216- // Using host floats (but it's fine, this operation does not have guaranteed precision).
217- let res = f1. to_host ( ) . powf ( f2. to_host ( ) ) . to_soft ( ) ;
218-
219- // Apply a relative error of 4ULP to introduce some non-determinism
220- // simulating imprecise implementations and optimizations.
221- math:: apply_random_float_error_ulp ( this, res, 4 )
222- } ) ;
223- let res = this. adjust_nan ( res, & [ f1, f2] ) ;
224- this. write_scalar ( res, dest) ?;
225- }
226- "powf32" => {
227- let [ f1, f2] = check_intrinsic_arg_count ( args) ?;
228- let f1 = this. read_scalar ( f1) ?. to_f32 ( ) ?;
229- let f2 = this. read_scalar ( f2) ?. to_f32 ( ) ?;
230-
231- let res =
232- math:: fixed_float_value ( this, intrinsic_name, & [ f1, f2] ) . unwrap_or_else ( || {
233- // Using host floats (but it's fine, this operation does not have guaranteed precision).
234- let res = f1. to_host ( ) . powf ( f2. to_host ( ) ) . to_soft ( ) ;
235-
236- // Apply a relative error of 4ULP to introduce some non-determinism
237- // simulating imprecise implementations and optimizations.
238- math:: apply_random_float_error_ulp ( this, res, 4 )
239- } ) ;
240- let res = this. adjust_nan ( res, & [ f1, f2] ) ;
241- this. write_scalar ( res, dest) ?;
242- }
243- "powf64" => {
244- let [ f1, f2] = check_intrinsic_arg_count ( args) ?;
245- let f1 = this. read_scalar ( f1) ?. to_f64 ( ) ?;
246- let f2 = this. read_scalar ( f2) ?. to_f64 ( ) ?;
247-
248- let res =
249- math:: fixed_float_value ( this, intrinsic_name, & [ f1, f2] ) . unwrap_or_else ( || {
250- // Using host floats (but it's fine, this operation does not have guaranteed precision).
251- let res = f1. to_host ( ) . powf ( f2. to_host ( ) ) . to_soft ( ) ;
252-
253- // Apply a relative error of 4ULP to introduce some non-determinism
254- // simulating imprecise implementations and optimizations.
255- math:: apply_random_float_error_ulp ( this, res, 4 )
256- } ) ;
257- let res = this. adjust_nan ( res, & [ f1, f2] ) ;
258- this. write_scalar ( res, dest) ?;
259- }
192+ "powf16" => pow_intrinsic :: < HalfS > ( this, args, dest) ?,
193+ "powf32" => pow_intrinsic :: < SingleS > ( this, args, dest) ?,
194+ "powf64" => pow_intrinsic :: < DoubleS > ( this, args, dest) ?,
260195
261- "powif16" => {
262- let [ f, i] = check_intrinsic_arg_count ( args) ?;
263- let f = this. read_scalar ( f) ?. to_f16 ( ) ?;
264- let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
265-
266- let res = math:: fixed_powi_value ( this, f, i) . unwrap_or_else ( || {
267- // Using host floats (but it's fine, this operation does not have guaranteed precision).
268- let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
269-
270- // Apply a relative error of 4ULP to introduce some non-determinism
271- // simulating imprecise implementations and optimizations.
272- math:: apply_random_float_error_ulp ( this, res, 4 )
273- } ) ;
274- let res = this. adjust_nan ( res, & [ f] ) ;
275- this. write_scalar ( res, dest) ?;
276- }
277- "powif32" => {
278- let [ f, i] = check_intrinsic_arg_count ( args) ?;
279- let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
280- let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
281-
282- let res = math:: fixed_powi_value ( this, f, i) . unwrap_or_else ( || {
283- // Using host floats (but it's fine, this operation does not have guaranteed precision).
284- let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
285-
286- // Apply a relative error of 4ULP to introduce some non-determinism
287- // simulating imprecise implementations and optimizations.
288- math:: apply_random_float_error_ulp ( this, res, 4 )
289- } ) ;
290- let res = this. adjust_nan ( res, & [ f] ) ;
291- this. write_scalar ( res, dest) ?;
292- }
293- "powif64" => {
294- let [ f, i] = check_intrinsic_arg_count ( args) ?;
295- let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
296- let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
297-
298- let res = math:: fixed_powi_value ( this, f, i) . unwrap_or_else ( || {
299- // Using host floats (but it's fine, this operation does not have guaranteed precision).
300- let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
301-
302- // Apply a relative error of 4ULP to introduce some non-determinism
303- // simulating imprecise implementations and optimizations.
304- math:: apply_random_float_error_ulp ( this, res, 4 )
305- } ) ;
306- let res = this. adjust_nan ( res, & [ f] ) ;
307- this. write_scalar ( res, dest) ?;
308- }
196+ "powif16" => powi_intrinsic :: < HalfS > ( this, args, dest) ?,
197+ "powif32" => powi_intrinsic :: < SingleS > ( this, args, dest) ?,
198+ "powif64" => powi_intrinsic :: < DoubleS > ( this, args, dest) ?,
309199
310200 _ => return interp_ok ( EmulateItemResult :: NotSupported ) ,
311201 }
0 commit comments