From f297516b7a728f8d5a64928b62ae1a920be043a7 Mon Sep 17 00:00:00 2001 From: Vyacheslav Egorov Date: Tue, 15 Oct 2019 20:27:12 +0000 Subject: [PATCH] [vm/simarm] Fix VRECPS/VRSQRTSQS instruction implementation. This instruction handles 0.0 and infinity operands specially because otherwise it produces NaN where it should produce appropriate infinity or zero. Fixes https://github.com/dart-lang/sdk/issues/24399 Fixes https://github.com/dart-lang/sdk/issues/26675 Fixes https://github.com/dart-lang/sdk/issues/38844 This relands commit 3da9c349d4468df5976339bc2b66bcfbf60e7f1d Change-Id: I116cea3b6c27b5dc16741f9652fbbb9a3ec1194e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121705 Commit-Queue: Vyacheslav Egorov Reviewed-by: Alexander Markov --- assembler_arm_test.cc | 143 +++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 93 deletions(-) diff --git a/assembler_arm_test.cc b/assembler_arm_test.cc index ca70de7cccab..c2c90308beec 100644 --- a/assembler_arm_test.cc +++ b/assembler_arm_test.cc @@ -14,6 +14,54 @@ namespace dart { namespace compiler { +TEST_CASE(ReciprocalOps) { + EXPECT_EQ(true, isinf(ReciprocalEstimate(-0.0f))); + EXPECT_EQ(true, signbit(ReciprocalEstimate(-0.0f))); + EXPECT_EQ(true, isinf(ReciprocalEstimate(0.0f))); + EXPECT_EQ(true, !signbit(ReciprocalEstimate(0.0f))); + EXPECT_EQ(true, isnan(ReciprocalEstimate(NAN))); + +#define AS_UINT32(v) (bit_cast(v)) +#define EXPECT_BITWISE_EQ(a, b) EXPECT_EQ(AS_UINT32(a), AS_UINT32(b)) + + EXPECT_BITWISE_EQ(0.0f, ReciprocalEstimate(kPosInfinity)); + EXPECT_BITWISE_EQ(-0.0f, ReciprocalEstimate(kNegInfinity)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(0.0f, kPosInfinity)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(0.0f, kNegInfinity)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(-0.0f, kPosInfinity)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(-0.0f, kNegInfinity)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kPosInfinity, 0.0f)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kNegInfinity, 0.0f)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kPosInfinity, -0.0f)); + EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kNegInfinity, -0.0f)); + EXPECT_EQ(true, isnan(ReciprocalStep(NAN, 1.0f))); + EXPECT_EQ(true, isnan(ReciprocalStep(1.0f, NAN))); + + EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(-1.0f))); + EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(kNegInfinity))); + EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(-1.0f))); + EXPECT_EQ(true, isinf(ReciprocalSqrtEstimate(-0.0f))); + EXPECT_EQ(true, signbit(ReciprocalSqrtEstimate(-0.0f))); + EXPECT_EQ(true, isinf(ReciprocalSqrtEstimate(0.0f))); + EXPECT_EQ(true, !signbit(ReciprocalSqrtEstimate(0.0f))); + EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(NAN))); + EXPECT_BITWISE_EQ(0.0f, ReciprocalSqrtEstimate(kPosInfinity)); + + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(0.0f, kPosInfinity)); + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(0.0f, kNegInfinity)); + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(-0.0f, kPosInfinity)); + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(-0.0f, kNegInfinity)); + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kPosInfinity, 0.0f)); + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kNegInfinity, 0.0f)); + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kPosInfinity, -0.0f)); + EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kNegInfinity, -0.0f)); + EXPECT_EQ(true, isnan(ReciprocalSqrtStep(NAN, 1.0f))); + EXPECT_EQ(true, isnan(ReciprocalSqrtStep(1.0f, NAN))); + +#undef AS_UINT32 +#undef EXPECT_BITWISE_EQ +} + #define __ assembler-> ASSEMBLER_TEST_GENERATE(Simple, assembler) { @@ -3430,43 +3478,6 @@ ASSEMBLER_TEST_RUN(Vmaxqs, test) { } } -// This is the same function as in the Simulator. -static float arm_recip_estimate(float a) { - // From the ARM Architecture Reference Manual A2-85. - if (isinf(a) || (fabs(a) >= exp2f(126))) - return 0.0; - else if (a == 0.0) - return kPosInfinity; - else if (isnan(a)) - return a; - - uint32_t a_bits = bit_cast(a); - // scaled = '0011 1111 1110' : a<22:0> : Zeros(29) - uint64_t scaled = (static_cast(0x3fe) << 52) | - ((static_cast(a_bits) & 0x7fffff) << 29); - // result_exp = 253 - UInt(a<30:23>) - int32_t result_exp = 253 - ((a_bits >> 23) & 0xff); - ASSERT((result_exp >= 1) && (result_exp <= 252)); - - double scaled_d = bit_cast(scaled); - ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0)); - - // a in units of 1/512 rounded down. - int32_t q = static_cast(scaled_d * 512.0); - // reciprocal r. - double r = 1.0 / ((static_cast(q) + 0.5) / 512.0); - // r in units of 1/256 rounded to nearest. - int32_t s = static_cast(256.0 * r + 0.5); - double estimate = static_cast(s) / 256.0; - ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0))); - - // result = sign : result_exp<7:0> : estimate<51:29> - int32_t result_bits = - (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) | - ((bit_cast(estimate) >> 29) & 0x7fffff); - return bit_cast(result_bits); -} - ASSEMBLER_TEST_GENERATE(Vrecpeqs, assembler) { if (TargetCPUFeatures::neon_supported()) { __ LoadSImmediate(S4, 147.0); @@ -3483,7 +3494,7 @@ ASSEMBLER_TEST_RUN(Vrecpeqs, test) { if (TargetCPUFeatures::neon_supported()) { typedef float (*Vrecpeqs)() DART_UNUSED; float res = EXECUTE_TEST_CODE_FLOAT(Vrecpeqs, test->entry()); - EXPECT_FLOAT_EQ(arm_recip_estimate(147.0), res, 0.0001f); + EXPECT_FLOAT_EQ(ReciprocalEstimate(147.0), res, 0.0001f); } } @@ -3540,60 +3551,6 @@ ASSEMBLER_TEST_RUN(Reciprocal, test) { } } -static float arm_reciprocal_sqrt_estimate(float a) { - // From the ARM Architecture Reference Manual A2-87. - if (isinf(a) || (fabs(a) >= exp2f(126))) - return 0.0; - else if (a == 0.0) - return kPosInfinity; - else if (isnan(a)) - return a; - - uint32_t a_bits = bit_cast(a); - uint64_t scaled; - if (((a_bits >> 23) & 1) != 0) { - // scaled = '0 01111111101' : operand<22:0> : Zeros(29) - scaled = (static_cast(0x3fd) << 52) | - ((static_cast(a_bits) & 0x7fffff) << 29); - } else { - // scaled = '0 01111111110' : operand<22:0> : Zeros(29) - scaled = (static_cast(0x3fe) << 52) | - ((static_cast(a_bits) & 0x7fffff) << 29); - } - // result_exp = (380 - UInt(operand<30:23>) DIV 2; - int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2; - - double scaled_d = bit_cast(scaled); - ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0)); - - double r; - if (scaled_d < 0.5) { - // range 0.25 <= a < 0.5 - - // a in units of 1/512 rounded down. - int32_t q0 = static_cast(scaled_d * 512.0); - // reciprocal root r. - r = 1.0 / sqrt((static_cast(q0) + 0.5) / 512.0); - } else { - // range 0.5 <= a < 1.0 - - // a in units of 1/256 rounded down. - int32_t q1 = static_cast(scaled_d * 256.0); - // reciprocal root r. - r = 1.0 / sqrt((static_cast(q1) + 0.5) / 256.0); - } - // r in units of 1/256 rounded to nearest. - int32_t s = static_cast(256.0 * r + 0.5); - double estimate = static_cast(s) / 256.0; - ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0))); - - // result = 0 : result_exp<7:0> : estimate<51:29> - int32_t result_bits = - ((result_exp & 0xff) << 23) | - ((bit_cast(estimate) >> 29) & 0x7fffff); - return bit_cast(result_bits); -} - ASSEMBLER_TEST_GENERATE(Vrsqrteqs, assembler) { if (TargetCPUFeatures::neon_supported()) { __ LoadSImmediate(S4, 147.0); @@ -3611,7 +3568,7 @@ ASSEMBLER_TEST_RUN(Vrsqrteqs, test) { if (TargetCPUFeatures::neon_supported()) { typedef float (*Vrsqrteqs)() DART_UNUSED; float res = EXECUTE_TEST_CODE_FLOAT(Vrsqrteqs, test->entry()); - EXPECT_FLOAT_EQ(arm_reciprocal_sqrt_estimate(147.0), res, 0.0001f); + EXPECT_FLOAT_EQ(ReciprocalSqrtEstimate(147.0), res, 0.0001f); } }