From 0fb66f092b897b55318509c6582008b3f912311a Mon Sep 17 00:00:00 2001 From: Sophie Kirschner Date: Fri, 10 Feb 2017 11:20:45 -0500 Subject: [PATCH] Fix issue 17562 - tan returning -nan for inputs where abs(x) >= 2^63 The fptan instruction pushes a 1.0 onto the FPU register stack after a successful operation, but when abs(input) >= 2^63 the C2 flag is set to indicate that the input was out of bounds, and it doesn't push the 1.0. Prior to this PR, the top value of the FPU stack was popped irrespective of whether C2 was set, which in the case of an out-of-bounds input caused the input to be removed from the stack and ultimately resulted in an incorrect return value of -nan. This PR changes this behavior, only popping after fptan when C2 was not set. See: http://x86.renejeschke.de/html/file_module_x86_id_109.html * Added unit tests for handling out-of-range inputs of fptan --- std/math.d | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/std/math.d b/std/math.d index 0ce6f21e114..1245abbafb2 100644 --- a/std/math.d +++ b/std/math.d @@ -768,10 +768,9 @@ real tan(real x) @trusted pure nothrow @nogc jc trigerr ; // x is NAN, infinity, or empty // 387's can handle subnormals SC18: fptan ; - fstp ST(0) ; // dump X, which is always 1 fstsw AX ; sahf ; - jnp Lret ; // C2 = 1 (x is out of range) + jnp Clear1 ; // C2 = 1 (x is out of range) // Do argument reduction to bring x into range fldpi ; @@ -789,6 +788,10 @@ trigerr: } return real.nan; +Clear1: asm pure nothrow @nogc{ + fstp ST(0) ; // dump X, which is always 1 + } + Lret: {} } else version(D_InlineAsm_X86_64) @@ -815,10 +818,9 @@ Lret: {} jnz trigerr ; // x is NAN, infinity, or empty // 387's can handle subnormals SC18: fptan ; - fstp ST(0) ; // dump X, which is always 1 fstsw AX ; test AH,4 ; - jz Lret ; // C2 = 1 (x is out of range) + jz Clear1 ; // C2 = 1 (x is out of range) // Do argument reduction to bring x into range fldpi ; @@ -837,6 +839,10 @@ trigerr: } return real.nan; +Clear1: asm pure nothrow @nogc{ + fstp ST(0) ; // dump X, which is always 1 + } + Lret: {} } else @@ -7174,6 +7180,12 @@ deprecated("Phobos1 math functions are deprecated, use isInfinity ") alias isinf real r = tan(-2.0L); assert(fabs(r - 2.18504f) < .00001); + + // Verify correct behavior for large inputs + assert(!isNaN(tan(0x1p63))); + assert(!isNaN(tan(0x1p300L))); + assert(!isNaN(tan(-0x1p63))); + assert(!isNaN(tan(-0x1p300L))); } @safe pure nothrow unittest