1
1
use std:: num:: NonZero ;
2
- use std:: ops:: Neg ;
3
2
use std:: time:: Duration ;
4
3
use std:: { cmp, iter} ;
5
4
6
- use rand:: { Rng , RngCore } ;
5
+ use rand:: RngCore ;
7
6
use rustc_abi:: { Align , CanonAbi , ExternAbi , FieldIdx , FieldsShape , Size , Variants } ;
8
7
use rustc_apfloat:: Float ;
9
- use rustc_apfloat:: ieee:: { Double , Half , IeeeFloat , Quad , Semantics , Single } ;
8
+ use rustc_apfloat:: ieee:: { Double , Half , Quad , Single } ;
10
9
use rustc_hir:: Safety ;
11
10
use rustc_hir:: def:: { DefKind , Namespace } ;
12
11
use rustc_hir:: def_id:: { CRATE_DEF_INDEX , CrateNum , DefId , LOCAL_CRATE } ;
@@ -15,13 +14,12 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
15
14
use rustc_middle:: middle:: dependency_format:: Linkage ;
16
15
use rustc_middle:: middle:: exported_symbols:: ExportedSymbol ;
17
16
use 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 } ;
19
18
use rustc_session:: config:: CrateType ;
20
19
use rustc_span:: { Span , Symbol } ;
21
20
use rustc_symbol_mangling:: mangle_internal_symbol;
22
21
use rustc_target:: callconv:: FnAbi ;
23
22
24
- use crate :: math:: { IeeeExt , apply_random_float_error_ulp} ;
25
23
use crate :: * ;
26
24
27
25
/// Indicates which kind of access is being performed.
@@ -217,57 +215,6 @@ impl ToSoft for f32 {
217
215
}
218
216
}
219
217
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
-
271
218
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
272
219
pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
273
220
/// Checks if the given crate/module exists.
@@ -1252,200 +1199,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
1252
1199
}
1253
1200
}
1254
1201
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
-
1449
1202
/// Returns an integer type that is twice wide as `ty`
1450
1203
fn get_twice_wide_int_ty ( & self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
1451
1204
let this = self . eval_context_ref ( ) ;
0 commit comments