11use std:: num:: NonZero ;
2- use std:: ops:: Neg ;
32use std:: time:: Duration ;
43use std:: { cmp, iter} ;
54
6- use rand:: { Rng , RngCore } ;
5+ use rand:: RngCore ;
76use rustc_abi:: { Align , CanonAbi , ExternAbi , FieldIdx , FieldsShape , Size , Variants } ;
87use rustc_apfloat:: Float ;
9- use rustc_apfloat:: ieee:: { Double , Half , IeeeFloat , Quad , Semantics , Single } ;
8+ use rustc_apfloat:: ieee:: { Double , Half , Quad , Single } ;
109use rustc_hir:: Safety ;
1110use rustc_hir:: def:: { DefKind , Namespace } ;
1211use rustc_hir:: def_id:: { CRATE_DEF_INDEX , CrateNum , DefId , LOCAL_CRATE } ;
@@ -15,13 +14,12 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1514use rustc_middle:: middle:: dependency_format:: Linkage ;
1615use rustc_middle:: middle:: exported_symbols:: ExportedSymbol ;
1716use rustc_middle:: ty:: layout:: { LayoutOf , MaybeResult , TyAndLayout } ;
18- use rustc_middle:: ty:: { self , Binder , FloatTy , FnSig , IntTy , ScalarInt , Ty , TyCtxt , UintTy } ;
17+ use rustc_middle:: ty:: { self , Binder , FloatTy , FnSig , IntTy , Ty , TyCtxt , UintTy } ;
1918use rustc_session:: config:: CrateType ;
2019use rustc_span:: { Span , Symbol } ;
2120use rustc_symbol_mangling:: mangle_internal_symbol;
2221use rustc_target:: callconv:: FnAbi ;
2322
24- use crate :: math:: { IeeeExt , apply_random_float_error_ulp} ;
2523use crate :: * ;
2624
2725/// Indicates which kind of access is being performed.
@@ -217,57 +215,6 @@ impl ToSoft for f32 {
217215 }
218216}
219217
220- /// Given a floating-point operation and a floating-point value, clamps the result to the output
221- /// range of the given operation according to the C standard, if any.
222- pub fn clamp_float_value < S : Semantics > ( intrinsic_name : & str , val : IeeeFloat < S > ) -> IeeeFloat < S >
223- where
224- IeeeFloat < S > : IeeeExt ,
225- {
226- let zero = IeeeFloat :: < S > :: ZERO ;
227- let one = IeeeFloat :: < S > :: one ( ) ;
228- let two = IeeeFloat :: < S > :: two ( ) ;
229- let pi = IeeeFloat :: < S > :: pi ( ) ;
230- let pi_over_2 = ( pi / two) . value ;
231-
232- match intrinsic_name {
233- // sin, cos, tanh: [-1, 1]
234- #[ rustfmt:: skip]
235- | "sinf32"
236- | "sinf64"
237- | "cosf32"
238- | "cosf64"
239- | "tanhf"
240- | "tanh"
241- => val. clamp ( one. neg ( ) , one) ,
242-
243- // exp: [0, +INF)
244- "expf32" | "exp2f32" | "expf64" | "exp2f64" => val. maximum ( zero) ,
245-
246- // cosh: [1, +INF)
247- "coshf" | "cosh" => val. maximum ( one) ,
248-
249- // acos: [0, π]
250- "acosf" | "acos" => val. clamp ( zero, pi) ,
251-
252- // asin: [-π, +π]
253- "asinf" | "asin" => val. clamp ( pi. neg ( ) , pi) ,
254-
255- // atan: (-π/2, +π/2)
256- "atanf" | "atan" => val. clamp ( pi_over_2. neg ( ) , pi_over_2) ,
257-
258- // erfc: (-1, 1)
259- "erff" | "erf" => val. clamp ( one. neg ( ) , one) ,
260-
261- // erfc: (0, 2)
262- "erfcf" | "erfc" => val. clamp ( zero, two) ,
263-
264- // atan2(y, x): arctan(y/x) in [−π, +π]
265- "atan2f" | "atan2" => val. clamp ( pi. neg ( ) , pi) ,
266-
267- _ => val,
268- }
269- }
270-
271218impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
272219pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
273220 /// Checks if the given crate/module exists.
@@ -1252,200 +1199,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12521199 }
12531200 }
12541201
1255- /// Applies a random ULP floating point error to `val` and returns the new value.
1256- /// So if you want an X ULP error, `ulp_exponent` should be log2(X).
1257- ///
1258- /// Will fail if `val` is not a floating point number.
1259- fn apply_random_float_error_to_imm (
1260- & mut self ,
1261- val : ImmTy < ' tcx > ,
1262- ulp_exponent : u32 ,
1263- ) -> InterpResult < ' tcx , ImmTy < ' tcx > > {
1264- let this = self . eval_context_mut ( ) ;
1265- let scalar = val. to_scalar_int ( ) ?;
1266- let res: ScalarInt = match val. layout . ty . kind ( ) {
1267- ty:: Float ( FloatTy :: F16 ) =>
1268- apply_random_float_error_ulp ( this, scalar. to_f16 ( ) , ulp_exponent) . into ( ) ,
1269- ty:: Float ( FloatTy :: F32 ) =>
1270- apply_random_float_error_ulp ( this, scalar. to_f32 ( ) , ulp_exponent) . into ( ) ,
1271- ty:: Float ( FloatTy :: F64 ) =>
1272- apply_random_float_error_ulp ( this, scalar. to_f64 ( ) , ulp_exponent) . into ( ) ,
1273- ty:: Float ( FloatTy :: F128 ) =>
1274- apply_random_float_error_ulp ( this, scalar. to_f128 ( ) , ulp_exponent) . into ( ) ,
1275- _ => bug ! ( "intrinsic called with non-float input type" ) ,
1276- } ;
1277-
1278- interp_ok ( ImmTy :: from_scalar_int ( res, val. layout ) )
1279- }
1280-
1281- /// For the intrinsics:
1282- /// - sinf32, sinf64, sinhf, sinh
1283- /// - cosf32, cosf64, coshf, cosh
1284- /// - tanhf, tanh, atanf, atan, atan2f, atan2
1285- /// - expf32, expf64, exp2f32, exp2f64
1286- /// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
1287- /// - powf32, powf64
1288- /// - erff, erf, erfcf, erfc
1289- /// - hypotf, hypot
1290- ///
1291- /// # Return
1292- ///
1293- /// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
1294- /// (specifically, C23 annex F.10) when given `args` as arguments. Outputs that are unaffected by a relative error
1295- /// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
1296- /// implementation. Returns `None` if no specific value is guaranteed.
1297- ///
1298- /// # Note
1299- ///
1300- /// For `powf*` operations of the form:
1301- ///
1302- /// - `(SNaN)^(±0)`
1303- /// - `1^(SNaN)`
1304- ///
1305- /// The result is implementation-defined:
1306- /// - musl returns for both `1.0`
1307- /// - glibc returns for both `NaN`
1308- ///
1309- /// This discrepancy exists because SNaN handling is not consistently defined across platforms,
1310- /// and the C standard leaves behavior for SNaNs unspecified.
1311- ///
1312- /// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
1313- fn fixed_float_value < S : Semantics > (
1314- & mut self ,
1315- intrinsic_name : & str ,
1316- args : & [ IeeeFloat < S > ] ,
1317- ) -> Option < IeeeFloat < S > >
1318- where
1319- IeeeFloat < S > : IeeeExt ,
1320- {
1321- let this = self . eval_context_mut ( ) ;
1322- let one = IeeeFloat :: < S > :: one ( ) ;
1323- let two = IeeeFloat :: < S > :: two ( ) ;
1324- let three = IeeeFloat :: < S > :: three ( ) ;
1325- let pi = IeeeFloat :: < S > :: pi ( ) ;
1326- let pi_over_2 = ( pi / two) . value ;
1327- let pi_over_4 = ( pi_over_2 / two) . value ;
1328-
1329- Some ( match ( intrinsic_name, args) {
1330- // cos(±0) and cosh(±0)= 1
1331- ( "cosf32" | "cosf64" | "coshf" | "cosh" , [ input] ) if input. is_zero ( ) => one,
1332-
1333- // e^0 = 1
1334- ( "expf32" | "expf64" | "exp2f32" | "exp2f64" , [ input] ) if input. is_zero ( ) => one,
1335-
1336- // tanh(±INF) = ±1
1337- ( "tanhf" | "tanh" , [ input] ) if input. is_infinite ( ) => one. copy_sign ( * input) ,
1338-
1339- // atan(±INF) = ±π/2
1340- ( "atanf" | "atan" , [ input] ) if input. is_infinite ( ) => pi_over_2. copy_sign ( * input) ,
1341-
1342- // erf(±INF) = ±1
1343- ( "erff" | "erf" , [ input] ) if input. is_infinite ( ) => one. copy_sign ( * input) ,
1344-
1345- // erfc(-INF) = 2
1346- ( "erfcf" | "erfc" , [ input] ) if input. is_neg_infinity ( ) => ( one + one) . value ,
1347-
1348- // hypot(x, ±0) = abs(x), if x is not a NaN.
1349- ( "_hypotf" | "hypotf" | "_hypot" | "hypot" , [ x, y] ) if !x. is_nan ( ) && y. is_zero ( ) =>
1350- x. abs ( ) ,
1351-
1352- // atan2(±0,−0) = ±π.
1353- // atan2(±0, y) = ±π for y < 0.
1354- // Must check for non NaN because `y.is_negative()` also applies to NaN.
1355- ( "atan2f" | "atan2" , [ x, y] ) if ( x. is_zero ( ) && ( y. is_negative ( ) && !y. is_nan ( ) ) ) =>
1356- pi. copy_sign ( * x) ,
1357-
1358- // atan2(±x,−∞) = ±π for finite x > 0.
1359- ( "atan2f" | "atan2" , [ x, y] )
1360- if ( !x. is_zero ( ) && !x. is_infinite ( ) ) && y. is_neg_infinity ( ) =>
1361- pi. copy_sign ( * x) ,
1362-
1363- // atan2(x, ±0) = −π/2 for x < 0.
1364- // atan2(x, ±0) = π/2 for x > 0.
1365- // REVIEW: Above is from C23, do we simplify this to the following?
1366- // atan2(±x, 0) = ±π/2 if x is non-zero
1367- ( "atan2f" | "atan2" , [ x, y] ) if !x. is_zero ( ) && y. is_zero ( ) => pi_over_2. copy_sign ( * x) ,
1368-
1369- //atan2(±∞, −∞) = ±3π/4
1370- ( "atan2f" | "atan2" , [ x, y] ) if x. is_infinite ( ) && y. is_neg_infinity ( ) =>
1371- ( pi_over_4 * three) . value . copy_sign ( * x) ,
1372-
1373- //atan2(±∞, +∞) = ±π/4
1374- ( "atan2f" | "atan2" , [ x, y] ) if x. is_infinite ( ) && y. is_pos_infinity ( ) =>
1375- pi_over_4. copy_sign ( * x) ,
1376-
1377- // atan2(±∞, y) returns ±π/2 for finite y.
1378- ( "atan2f" | "atan2" , [ x, y] )
1379- if x. is_infinite ( ) && ( !y. is_infinite ( ) && !y. is_nan ( ) ) =>
1380- pi_over_2. copy_sign ( * x) ,
1381-
1382- // (-1)^(±INF) = 1
1383- ( "powf32" | "powf64" , [ base, exp] ) if * base == -one && exp. is_infinite ( ) => one,
1384-
1385- // 1^y = 1 for any y, even a NaN
1386- ( "powf32" | "powf64" , [ base, exp] ) if * base == one => {
1387- let rng = this. machine . rng . get_mut ( ) ;
1388- // SNaN exponents get special treatment: they might return 1, or a NaN.
1389- let return_nan = exp. is_signaling ( ) && this. machine . float_nondet && rng. random ( ) ;
1390- // Handle both the musl and glibc cases non-deterministically.
1391- if return_nan { this. generate_nan ( args) } else { one }
1392- }
1393-
1394- // x^(±0) = 1 for any x, even a NaN
1395- ( "powf32" | "powf64" , [ base, exp] ) if exp. is_zero ( ) => {
1396- let rng = this. machine . rng . get_mut ( ) ;
1397- // SNaN bases get special treatment: they might return 1, or a NaN.
1398- let return_nan = base. is_signaling ( ) && this. machine . float_nondet && rng. random ( ) ;
1399- // Handle both the musl and glibc cases non-deterministically.
1400- if return_nan { this. generate_nan ( args) } else { one }
1401- }
1402-
1403- // There are a lot of cases for fixed outputs according to the C Standard, but these are
1404- // mainly INF or zero which are not affected by the applied error.
1405- _ => return None ,
1406- } )
1407- }
1408-
1409- /// # Return
1410- ///
1411- /// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
1412- /// (specifically, C23 annex F.10) when given f (as a float) and int (as a i32) as arguments. Outputs that are
1413- /// unaffected by a relative error (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
1414- /// implementation. Returns `None` if no specific value is guaranteed.
1415- ///
1416- /// # Note
1417- ///
1418- /// For `powif*` operations of the form `(SNaN)^(±0)` we follow the same behaviour as `powf*`, see [`fixed_float_value`].
1419- fn fixed_float_int_value < S : Semantics > (
1420- & mut self ,
1421- operation : & str ,
1422- f : IeeeFloat < S > ,
1423- int : i32 ,
1424- ) -> Option < IeeeFloat < S > >
1425- where
1426- IeeeFloat < S > : IeeeExt ,
1427- {
1428- let this = self . eval_context_mut ( ) ;
1429-
1430- Some ( match ( operation, f, int) {
1431- ( "powif32" | "powif64" , x, 0 ) => {
1432- let one = IeeeFloat :: < S > :: one ( ) ;
1433- let rng = this. machine . rng . get_mut ( ) ;
1434- let return_nan = this. machine . float_nondet && rng. random ( ) && x. is_signaling ( ) ;
1435- // For SNaN treatment, we are consistent with `powf`above.
1436- // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
1437- // but for now we are maximally conservative.)
1438- if return_nan { this. generate_nan ( & [ x] ) } else { one }
1439- }
1440-
1441- // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
1442- // scalbn(x, 0) = x.
1443- ( "_ldexp" | "ldexp" | "scalbn" , x, 0 ) => x,
1444-
1445- _ => return None ,
1446- } )
1447- }
1448-
14491202 /// Returns an integer type that is twice wide as `ty`
14501203 fn get_twice_wide_int_ty ( & self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
14511204 let this = self . eval_context_ref ( ) ;
0 commit comments