@@ -102,6 +102,15 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
102102 }
103103 }
104104
105+ if cfg ! ( target_arch = "x86" ) {
106+ match ctx. fn_ident {
107+ // Input `fma(0.999999999999999, 1.0000000000000013, 0.0) = 1.0000000000000002` is
108+ // incorrect on i586 and i686.
109+ Id :: Fma => ulp = 1 ,
110+ _ => ( ) ,
111+ }
112+ }
113+
105114 // In some cases, our implementation is less accurate than musl on i586.
106115 if cfg ! ( x86_no_sse) {
107116 match ctx. fn_ident {
@@ -370,59 +379,129 @@ fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Opt
370379impl MaybeOverride < ( f16 , f16 ) > for SpecialCase {
371380 fn check_float < F : Float > (
372381 input : ( f16 , f16 ) ,
373- _actual : F ,
382+ actual : F ,
374383 expected : F ,
375384 _ulp : & mut u32 ,
376385 ctx : & CheckCtx ,
377386 ) -> Option < TestResult > {
378- maybe_skip_binop_nan ( input, expected, ctx)
387+ binop_common ( input, actual , expected, ctx)
379388 }
380389}
381390
382391impl MaybeOverride < ( f32 , f32 ) > for SpecialCase {
383392 fn check_float < F : Float > (
384393 input : ( f32 , f32 ) ,
385- _actual : F ,
394+ actual : F ,
386395 expected : F ,
387396 _ulp : & mut u32 ,
388397 ctx : & CheckCtx ,
389398 ) -> Option < TestResult > {
390- maybe_skip_binop_nan ( input, expected, ctx)
399+ if ctx. base_name == BaseName :: Fmin
400+ && input. 0 . biteq ( f32:: NEG_ZERO )
401+ && input. 1 . biteq ( f32:: ZERO )
402+ && expected. biteq ( F :: NEG_ZERO )
403+ && actual. biteq ( F :: ZERO )
404+ {
405+ return XFAIL ;
406+ }
407+
408+ binop_common ( input, actual, expected, ctx)
409+ }
410+
411+ fn check_int < I : Int > (
412+ _input : ( f32 , f32 ) ,
413+ actual : I ,
414+ expected : I ,
415+ ctx : & CheckCtx ,
416+ ) -> Option < TestResult > {
417+ remquo_common ( actual, expected, ctx)
391418 }
392419}
393420
394421impl MaybeOverride < ( f64 , f64 ) > for SpecialCase {
395422 fn check_float < F : Float > (
396423 input : ( f64 , f64 ) ,
397- _actual : F ,
424+ actual : F ,
398425 expected : F ,
399426 _ulp : & mut u32 ,
400427 ctx : & CheckCtx ,
401428 ) -> Option < TestResult > {
402- maybe_skip_binop_nan ( input, expected, ctx)
429+ if ctx. base_name == BaseName :: Fmin
430+ && input. 0 . biteq ( f64:: NEG_ZERO )
431+ && input. 1 . biteq ( f64:: ZERO )
432+ && expected. biteq ( F :: ZERO )
433+ && actual. biteq ( F :: NEG_ZERO )
434+ {
435+ return XFAIL ;
436+ }
437+
438+ binop_common ( input, actual, expected, ctx)
439+ }
440+
441+ fn check_int < I : Int > (
442+ _input : ( f64 , f64 ) ,
443+ actual : I ,
444+ expected : I ,
445+ ctx : & CheckCtx ,
446+ ) -> Option < TestResult > {
447+ remquo_common ( actual, expected, ctx)
448+ }
449+ }
450+
451+ fn remquo_common < I : Int > ( actual : I , expected : I , ctx : & CheckCtx ) -> Option < TestResult > {
452+ // FIXME: Our MPFR implementation disagrees with musl and may need to be updated.
453+ if ctx. basis == CheckBasis :: Mpfr
454+ && ctx. base_name == BaseName :: Remquo
455+ && expected == I :: MIN
456+ && actual == I :: ZERO
457+ {
458+ return XFAIL ;
403459 }
460+
461+ None
404462}
405463
406464#[ cfg( f128_enabled) ]
407465impl MaybeOverride < ( f128 , f128 ) > for SpecialCase {
408466 fn check_float < F : Float > (
409467 input : ( f128 , f128 ) ,
410- _actual : F ,
468+ actual : F ,
411469 expected : F ,
412470 _ulp : & mut u32 ,
413471 ctx : & CheckCtx ,
414472 ) -> Option < TestResult > {
415- maybe_skip_binop_nan ( input, expected, ctx)
473+ binop_common ( input, actual , expected, ctx)
416474 }
417475}
418476
419- /// Musl propagates NaNs if one is provided as the input, but we return the other input.
420477// F1 and F2 are always the same type, this is just to please generics
421- fn maybe_skip_binop_nan < F1 : Float , F2 : Float > (
478+ fn binop_common < F1 : Float , F2 : Float > (
422479 input : ( F1 , F1 ) ,
480+ actual : F2 ,
423481 expected : F2 ,
424482 ctx : & CheckCtx ,
425483) -> Option < TestResult > {
484+ /* FIXME(#439): we do not compare signed zeros */
485+
486+ if ctx. base_name == BaseName :: Fmin
487+ && input. 0 . biteq ( F1 :: NEG_ZERO )
488+ && input. 1 . biteq ( F1 :: ZERO )
489+ && expected. biteq ( F2 :: NEG_ZERO )
490+ && actual. biteq ( F2 :: ZERO )
491+ {
492+ return XFAIL ;
493+ }
494+
495+ if ctx. base_name == BaseName :: Fmax
496+ && input. 0 . biteq ( F1 :: NEG_ZERO )
497+ && input. 1 . biteq ( F1 :: ZERO )
498+ && expected. biteq ( F2 :: ZERO )
499+ && actual. biteq ( F2 :: NEG_ZERO )
500+ {
501+ return XFAIL ;
502+ }
503+
504+ // Musl propagates NaNs if one is provided as the input, but we return the other input.
426505 match ( & ctx. basis , ctx. base_name ) {
427506 ( Musl , BaseName :: Fmin | BaseName :: Fmax )
428507 if ( input. 0 . is_nan ( ) || input. 1 . is_nan ( ) ) && expected. is_nan ( ) =>
@@ -509,7 +588,53 @@ fn bessel_prec_dropoff<F: Float>(
509588 None
510589}
511590
512- impl MaybeOverride < ( f32 , f32 , f32 ) > for SpecialCase { }
513- impl MaybeOverride < ( f64 , f64 , f64 ) > for SpecialCase { }
514591impl MaybeOverride < ( f32 , i32 ) > for SpecialCase { }
515592impl MaybeOverride < ( f64 , i32 ) > for SpecialCase { }
593+
594+ impl MaybeOverride < ( f32 , f32 , f32 ) > for SpecialCase {
595+ fn check_float < F : Float > (
596+ input : ( f32 , f32 , f32 ) ,
597+ actual : F ,
598+ expected : F ,
599+ _ulp : & mut u32 ,
600+ ctx : & CheckCtx ,
601+ ) -> Option < TestResult > {
602+ ternop_common ( input, actual, expected, ctx)
603+ }
604+ }
605+ impl MaybeOverride < ( f64 , f64 , f64 ) > for SpecialCase {
606+ fn check_float < F : Float > (
607+ input : ( f64 , f64 , f64 ) ,
608+ actual : F ,
609+ expected : F ,
610+ _ulp : & mut u32 ,
611+ ctx : & CheckCtx ,
612+ ) -> Option < TestResult > {
613+ ternop_common ( input, actual, expected, ctx)
614+ }
615+ }
616+
617+ // F1 and F2 are always the same type, this is just to please generics
618+ fn ternop_common < F1 : Float , F2 : Float > (
619+ input : ( F1 , F1 , F1 ) ,
620+ actual : F2 ,
621+ expected : F2 ,
622+ ctx : & CheckCtx ,
623+ ) -> Option < TestResult > {
624+ // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result
625+ // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the
626+ // exact result". Our implementation returns the wrong sign:
627+ // fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0)
628+ if ctx. base_name == BaseName :: Fma
629+ && ( input. 0 . is_sign_negative ( ) ^ input. 1 . is_sign_negative ( ) )
630+ && input. 0 != F1 :: ZERO
631+ && input. 1 != F1 :: ZERO
632+ && input. 2 . biteq ( F1 :: ZERO )
633+ && expected. biteq ( F2 :: NEG_ZERO )
634+ && actual. biteq ( F2 :: ZERO )
635+ {
636+ return XFAIL ;
637+ }
638+
639+ None
640+ }
0 commit comments