@@ -121,6 +121,10 @@ mod tests {
121121 Subdf3 ,
122122 Subsf3 ,
123123
124+ // float/mul.rs
125+ Mulsf3 ,
126+ Muldf3 ,
127+
124128 // int/mul.rs
125129 Muldi3 ,
126130 Mulodi4 ,
@@ -3221,6 +3225,181 @@ fn subsf3() {
32213225 }
32223226 }
32233227
3228+ #[ derive( Eq , Hash , PartialEq ) ]
3229+ pub struct Mulsf3 {
3230+ a : u32 , // f32
3231+ b : u32 , // f32
3232+ c : u32 , // f32
3233+ }
3234+
3235+ impl TestCase for Mulsf3 {
3236+ fn name ( ) -> & ' static str {
3237+ "mulsf3"
3238+ }
3239+
3240+ fn generate < R > ( rng : & mut R ) -> Option < Self >
3241+ where
3242+ R : Rng ,
3243+ Self : Sized ,
3244+ {
3245+ let a = gen_large_f32 ( rng) ;
3246+ let b = gen_large_f32 ( rng) ;
3247+ let c = a * b;
3248+ // TODO accept NaNs. We don't do that right now because we can't check
3249+ // for NaN-ness on the thumb targets (due to missing intrinsics)
3250+ if a. is_nan ( ) || b. is_nan ( ) || c. is_nan ( ) {
3251+ return None ;
3252+ }
3253+
3254+ Some (
3255+ Mulsf3 {
3256+ a : to_u32 ( a) ,
3257+ b : to_u32 ( b) ,
3258+ c : to_u32 ( c) ,
3259+ } ,
3260+ )
3261+ }
3262+
3263+ fn to_string ( & self , buffer : & mut String ) {
3264+ writeln ! (
3265+ buffer,
3266+ "(({a}, {b}), {c})," ,
3267+ a = self . a,
3268+ b = self . b,
3269+ c = self . c
3270+ )
3271+ . unwrap ( ) ;
3272+ }
3273+
3274+ fn prologue ( ) -> & ' static str {
3275+ r#"
3276+ #[cfg(all(target_arch = "arm",
3277+ not(any(target_env = "gnu", target_env = "musl")),
3278+ target_os = "linux",
3279+ test))]
3280+ use core::mem;
3281+ #[cfg(not(all(target_arch = "arm",
3282+ not(any(target_env = "gnu", target_env = "musl")),
3283+ target_os = "linux",
3284+ test)))]
3285+ use std::mem;
3286+ use compiler_builtins::float::mul::__mulsf3;
3287+
3288+ fn mk_f32(x: u32) -> f32 {
3289+ unsafe { mem::transmute(x) }
3290+ }
3291+
3292+ fn to_u32(x: f32) -> u32 {
3293+ unsafe { mem::transmute(x) }
3294+ }
3295+
3296+ static TEST_CASES: &[((u32, u32), u32)] = &[
3297+ "#
3298+ }
3299+
3300+ fn epilogue ( ) -> & ' static str {
3301+ "
3302+ ];
3303+
3304+ #[test]
3305+ fn mulsf3() {
3306+ for &((a, b), c) in TEST_CASES {
3307+ let c_ = __mulsf3(mk_f32(a), mk_f32(b));
3308+ assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
3309+ }
3310+ }
3311+ "
3312+ }
3313+ }
3314+
3315+ #[ derive( Eq , Hash , PartialEq ) ]
3316+ pub struct Muldf3 {
3317+ a : u64 , // f64
3318+ b : u64 , // f64
3319+ c : u64 , // f64
3320+ }
3321+
3322+ impl TestCase for Muldf3 {
3323+ fn name ( ) -> & ' static str {
3324+ "muldf3"
3325+ }
3326+
3327+ fn generate < R > ( rng : & mut R ) -> Option < Self >
3328+ where
3329+ R : Rng ,
3330+ Self : Sized ,
3331+ {
3332+ let a = gen_large_f64 ( rng) ;
3333+ let b = gen_large_f64 ( rng) ;
3334+ let c = a * b;
3335+ // TODO accept NaNs. We don't do that right now because we can't check
3336+ // for NaN-ness on the thumb targets (due to missing intrinsics)
3337+ if a. is_nan ( ) || b. is_nan ( ) || c. is_nan ( ) {
3338+ return None ;
3339+ }
3340+
3341+ Some (
3342+ Muldf3 {
3343+ a : to_u64 ( a) ,
3344+ b : to_u64 ( b) ,
3345+ c : to_u64 ( c) ,
3346+ } ,
3347+ )
3348+ }
3349+
3350+ fn to_string ( & self , buffer : & mut String ) {
3351+ writeln ! (
3352+ buffer,
3353+ "(({a}, {b}), {c})," ,
3354+ a = self . a,
3355+ b = self . b,
3356+ c = self . c
3357+ )
3358+ . unwrap ( ) ;
3359+ }
3360+
3361+ fn prologue ( ) -> & ' static str {
3362+ r#"
3363+ #[cfg(all(target_arch = "arm",
3364+ not(any(target_env = "gnu", target_env = "musl")),
3365+ target_os = "linux",
3366+ test))]
3367+ use core::mem;
3368+ #[cfg(not(all(target_arch = "arm",
3369+ not(any(target_env = "gnu", target_env = "musl")),
3370+ target_os = "linux",
3371+ test)))]
3372+ use std::mem;
3373+ use compiler_builtins::float::mul::__muldf3;
3374+
3375+ fn mk_f64(x: u64) -> f64 {
3376+ unsafe { mem::transmute(x) }
3377+ }
3378+
3379+ fn to_u64(x: f64) -> u64 {
3380+ unsafe { mem::transmute(x) }
3381+ }
3382+
3383+ static TEST_CASES: &[((u64, u64), u64)] = &[
3384+ "#
3385+ }
3386+
3387+ fn epilogue ( ) -> & ' static str {
3388+ "
3389+ ];
3390+
3391+ #[test]
3392+ fn muldf3() {
3393+ for &((a, b), c) in TEST_CASES {
3394+ let c_ = __muldf3(mk_f64(a), mk_f64(b));
3395+ assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
3396+ }
3397+ }
3398+ "
3399+ }
3400+ }
3401+
3402+
32243403 #[ derive( Eq , Hash , PartialEq ) ]
32253404 pub struct Udivdi3 {
32263405 a : u64 ,
@@ -3899,6 +4078,57 @@ macro_rules! panic {
38994078 gen_float ! ( gen_f32, f32 , u32 , 32 , 23 ) ;
39004079 gen_float ! ( gen_f64, f64 , u64 , 64 , 52 ) ;
39014080
4081+ macro_rules! gen_large_float {
4082+ ( $name: ident,
4083+ $fty: ident,
4084+ $uty: ident,
4085+ $bits: expr,
4086+ $significand_bits: expr) => {
4087+ pub fn $name<R >( rng: & mut R ) -> $fty
4088+ where
4089+ R : Rng ,
4090+ {
4091+ const BITS : u8 = $bits;
4092+ const SIGNIFICAND_BITS : u8 = $significand_bits;
4093+
4094+ const SIGNIFICAND_MASK : $uty = ( 1 << SIGNIFICAND_BITS ) - 1 ;
4095+ const SIGN_MASK : $uty = ( 1 << ( BITS - 1 ) ) ;
4096+ const EXPONENT_MASK : $uty = !( SIGN_MASK | SIGNIFICAND_MASK ) ;
4097+
4098+ fn mk_f32( sign: bool , exponent: $uty, significand: $uty) -> $fty {
4099+ unsafe {
4100+ mem:: transmute( ( ( sign as $uty) << ( BITS - 1 ) ) |
4101+ ( ( exponent & EXPONENT_MASK ) <<
4102+ SIGNIFICAND_BITS ) |
4103+ ( significand & SIGNIFICAND_MASK ) )
4104+ }
4105+ }
4106+
4107+ if rng. gen_weighted_bool( 10 ) {
4108+ // Special values
4109+ * rng. choose( & [ -0.0 ,
4110+ 0.0 ,
4111+ :: std:: $fty:: NAN ,
4112+ :: std:: $fty:: INFINITY ,
4113+ -:: std:: $fty:: INFINITY ] )
4114+ . unwrap( )
4115+ } else if rng. gen_weighted_bool( 10 ) {
4116+ // NaN patterns
4117+ mk_f32( rng. gen ( ) , rng. gen ( ) , 0 )
4118+ } else if rng. gen ( ) {
4119+ // Denormalized
4120+ mk_f32( rng. gen ( ) , 0 , rng. gen ( ) )
4121+ } else {
4122+ // Random anything
4123+ rng. gen :: <$fty>( )
4124+ }
4125+ }
4126+ }
4127+ }
4128+
4129+ gen_large_float ! ( gen_large_f32, f32 , u32 , 32 , 23 ) ;
4130+ gen_large_float ! ( gen_large_f64, f64 , u64 , 64 , 52 ) ;
4131+
39024132 pub fn gen_u128 < R > ( rng : & mut R ) -> u128
39034133 where
39044134 R : Rng ,
0 commit comments